From 25d77892d72d455f8a89372687db45aefbc61cec Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Mon, 30 Sep 2013 14:03:48 +0300 Subject: move windows classes to windows directory. --- Android.mk | 1 + src/CMakeLists.txt | 180 +-- src/Makefile.am | 180 +-- src/actionmanager.cpp | 46 +- src/actorspritemanager.cpp | 6 +- src/being/being.cpp | 7 +- src/being/localplayer.cpp | 17 +- src/being/playerinfo.cpp | 6 +- src/client.cpp | 41 +- src/commands.cpp | 15 +- src/game.cpp | 43 +- src/gui/botcheckerwindow.cpp | 421 ------ src/gui/botcheckerwindow.h | 94 -- src/gui/buydialog.cpp | 553 -------- src/gui/buydialog.h | 163 --- src/gui/buyselldialog.cpp | 150 --- src/gui/buyselldialog.h | 83 -- src/gui/changeemaildialog.cpp | 181 --- src/gui/changeemaildialog.h | 80 -- src/gui/changepassworddialog.cpp | 172 --- src/gui/changepassworddialog.h | 75 -- src/gui/charcreatedialog.cpp | 698 ---------- src/gui/charcreatedialog.h | 165 --- src/gui/charselectdialog.cpp | 587 --------- src/gui/charselectdialog.h | 126 -- src/gui/chatwindow.cpp | 1794 -------------------------- src/gui/chatwindow.h | 378 ------ src/gui/confirmdialog.cpp | 109 -- src/gui/confirmdialog.h | 65 - src/gui/connectiondialog.cpp | 71 -- src/gui/connectiondialog.h | 64 - src/gui/debugwindow.cpp | 536 -------- src/gui/debugwindow.h | 165 --- src/gui/didyouknowwindow.cpp | 176 --- src/gui/didyouknowwindow.h | 78 -- src/gui/editdialog.cpp | 72 -- src/gui/editdialog.h | 69 - src/gui/editserverdialog.cpp | 300 ----- src/gui/editserverdialog.h | 113 -- src/gui/emotewindow.cpp | 229 ---- src/gui/emotewindow.h | 80 -- src/gui/equipmentwindow.cpp | 668 ---------- src/gui/equipmentwindow.h | 155 --- src/gui/helpwindow.cpp | 195 --- src/gui/helpwindow.h | 93 -- src/gui/inventorywindow.cpp | 833 ------------ src/gui/inventorywindow.h | 196 --- src/gui/itemamountwindow.cpp | 450 ------- src/gui/itemamountwindow.h | 126 -- src/gui/killstats.cpp | 520 -------- src/gui/killstats.h | 132 -- src/gui/logindialog.cpp | 413 ------ src/gui/logindialog.h | 108 -- src/gui/minimap.cpp | 484 ------- src/gui/minimap.h | 89 -- src/gui/ministatuswindow.cpp | 526 -------- src/gui/ministatuswindow.h | 135 -- src/gui/npcdialog.cpp | 960 -------------- src/gui/npcdialog.h | 301 ----- src/gui/npcpostdialog.cpp | 136 -- src/gui/npcpostdialog.h | 74 -- src/gui/okdialog.cpp | 89 -- src/gui/okdialog.h | 71 -- src/gui/outfitwindow.cpp | 662 ---------- src/gui/outfitwindow.h | 129 -- src/gui/popupmenu.cpp | 27 +- src/gui/questswindow.cpp | 567 --------- src/gui/questswindow.h | 106 -- src/gui/quitdialog.cpp | 256 ---- src/gui/quitdialog.h | 83 -- src/gui/registerdialog.cpp | 316 ----- src/gui/registerdialog.h | 112 -- src/gui/selldialog.cpp | 389 ------ src/gui/selldialog.h | 147 --- src/gui/serverdialog.cpp | 866 ------------- src/gui/serverdialog.h | 194 --- src/gui/setup.cpp | 254 ---- src/gui/setup.h | 82 -- src/gui/setup_chat.cpp | 2 +- src/gui/setup_input.cpp | 3 +- src/gui/setup_theme.cpp | 3 +- src/gui/setup_video.cpp | 4 +- src/gui/shopwindow.cpp | 867 ------------- src/gui/shopwindow.h | 178 --- src/gui/shortcutwindow.cpp | 242 ---- src/gui/shortcutwindow.h | 90 -- src/gui/skilldialog.cpp | 721 ----------- src/gui/skilldialog.h | 109 -- src/gui/socialwindow.cpp | 1894 --------------------------- src/gui/socialwindow.h | 170 --- src/gui/statuswindow.cpp | 886 ------------- src/gui/statuswindow.h | 125 -- src/gui/textcommandeditor.cpp | 396 ------ src/gui/textcommandeditor.h | 103 -- src/gui/textdialog.cpp | 131 -- src/gui/textdialog.h | 80 -- src/gui/tradewindow.cpp | 485 ------- src/gui/tradewindow.h | 187 --- src/gui/unregisterdialog.cpp | 154 --- src/gui/unregisterdialog.h | 70 - src/gui/updaterwindow.cpp | 943 -------------- src/gui/updaterwindow.h | 258 ---- src/gui/viewport.cpp | 3 +- src/gui/whoisonline.cpp | 865 ------------- src/gui/whoisonline.h | 223 ---- src/gui/widgets/avatarlistbox.cpp | 3 +- src/gui/widgets/characterdisplay.cpp | 3 +- src/gui/widgets/characterviewbase.h | 2 +- src/gui/widgets/chattab.cpp | 2 +- src/gui/widgets/chattab.h | 2 +- src/gui/widgets/dropshortcutcontainer.cpp | 3 +- src/gui/widgets/itemcontainer.cpp | 7 +- src/gui/widgets/itemlinkhandler.cpp | 5 +- src/gui/widgets/itemshortcutcontainer.cpp | 5 +- src/gui/widgets/setupitem.cpp | 3 +- src/gui/widgets/spellshortcutcontainer.cpp | 5 +- src/gui/windowmenu.cpp | 7 +- src/gui/windows/botcheckerwindow.cpp | 421 ++++++ src/gui/windows/botcheckerwindow.h | 94 ++ src/gui/windows/buydialog.cpp | 553 ++++++++ src/gui/windows/buydialog.h | 163 +++ src/gui/windows/buyselldialog.cpp | 150 +++ src/gui/windows/buyselldialog.h | 83 ++ src/gui/windows/changeemaildialog.cpp | 181 +++ src/gui/windows/changeemaildialog.h | 80 ++ src/gui/windows/changepassworddialog.cpp | 172 +++ src/gui/windows/changepassworddialog.h | 75 ++ src/gui/windows/charcreatedialog.cpp | 698 ++++++++++ src/gui/windows/charcreatedialog.h | 165 +++ src/gui/windows/charselectdialog.cpp | 587 +++++++++ src/gui/windows/charselectdialog.h | 126 ++ src/gui/windows/chatwindow.cpp | 1795 ++++++++++++++++++++++++++ src/gui/windows/chatwindow.h | 378 ++++++ src/gui/windows/confirmdialog.cpp | 109 ++ src/gui/windows/confirmdialog.h | 65 + src/gui/windows/connectiondialog.cpp | 71 ++ src/gui/windows/connectiondialog.h | 64 + src/gui/windows/debugwindow.cpp | 537 ++++++++ src/gui/windows/debugwindow.h | 165 +++ src/gui/windows/didyouknowwindow.cpp | 177 +++ src/gui/windows/didyouknowwindow.h | 78 ++ src/gui/windows/editdialog.cpp | 72 ++ src/gui/windows/editdialog.h | 69 + src/gui/windows/editserverdialog.cpp | 300 +++++ src/gui/windows/editserverdialog.h | 113 ++ src/gui/windows/emotewindow.cpp | 229 ++++ src/gui/windows/emotewindow.h | 80 ++ src/gui/windows/equipmentwindow.cpp | 669 ++++++++++ src/gui/windows/equipmentwindow.h | 155 +++ src/gui/windows/helpwindow.cpp | 196 +++ src/gui/windows/helpwindow.h | 93 ++ src/gui/windows/inventorywindow.cpp | 835 ++++++++++++ src/gui/windows/inventorywindow.h | 196 +++ src/gui/windows/itemamountwindow.cpp | 451 +++++++ src/gui/windows/itemamountwindow.h | 126 ++ src/gui/windows/killstats.cpp | 520 ++++++++ src/gui/windows/killstats.h | 132 ++ src/gui/windows/logindialog.cpp | 413 ++++++ src/gui/windows/logindialog.h | 108 ++ src/gui/windows/minimap.cpp | 485 +++++++ src/gui/windows/minimap.h | 89 ++ src/gui/windows/ministatuswindow.cpp | 527 ++++++++ src/gui/windows/ministatuswindow.h | 135 ++ src/gui/windows/npcdialog.cpp | 961 ++++++++++++++ src/gui/windows/npcdialog.h | 301 +++++ src/gui/windows/npcpostdialog.cpp | 136 ++ src/gui/windows/npcpostdialog.h | 74 ++ src/gui/windows/okdialog.cpp | 89 ++ src/gui/windows/okdialog.h | 71 ++ src/gui/windows/outfitwindow.cpp | 662 ++++++++++ src/gui/windows/outfitwindow.h | 129 ++ src/gui/windows/questswindow.cpp | 567 +++++++++ src/gui/windows/questswindow.h | 106 ++ src/gui/windows/quitdialog.cpp | 256 ++++ src/gui/windows/quitdialog.h | 83 ++ src/gui/windows/registerdialog.cpp | 316 +++++ src/gui/windows/registerdialog.h | 112 ++ src/gui/windows/selldialog.cpp | 389 ++++++ src/gui/windows/selldialog.h | 147 +++ src/gui/windows/serverdialog.cpp | 867 +++++++++++++ src/gui/windows/serverdialog.h | 194 +++ src/gui/windows/setup.cpp | 255 ++++ src/gui/windows/setup.h | 82 ++ src/gui/windows/shopwindow.cpp | 866 +++++++++++++ src/gui/windows/shopwindow.h | 179 +++ src/gui/windows/shortcutwindow.cpp | 242 ++++ src/gui/windows/shortcutwindow.h | 90 ++ src/gui/windows/skilldialog.cpp | 722 +++++++++++ src/gui/windows/skilldialog.h | 109 ++ src/gui/windows/socialwindow.cpp | 1895 ++++++++++++++++++++++++++++ src/gui/windows/socialwindow.h | 170 +++ src/gui/windows/statuswindow.cpp | 888 +++++++++++++ src/gui/windows/statuswindow.h | 125 ++ src/gui/windows/textcommandeditor.cpp | 396 ++++++ src/gui/windows/textcommandeditor.h | 103 ++ src/gui/windows/textdialog.cpp | 131 ++ src/gui/windows/textdialog.h | 80 ++ src/gui/windows/tradewindow.cpp | 486 +++++++ src/gui/windows/tradewindow.h | 187 +++ src/gui/windows/unregisterdialog.cpp | 154 +++ src/gui/windows/unregisterdialog.h | 70 + src/gui/windows/updaterwindow.cpp | 943 ++++++++++++++ src/gui/windows/updaterwindow.h | 258 ++++ src/gui/windows/whoisonline.cpp | 866 +++++++++++++ src/gui/windows/whoisonline.h | 223 ++++ src/gui/windows/worldselectdialog.cpp | 166 +++ src/gui/windows/worldselectdialog.h | 74 ++ src/gui/worldselectdialog.cpp | 166 --- src/gui/worldselectdialog.h | 74 -- src/guildmanager.cpp | 2 +- src/input/inputmanager.cpp | 16 +- src/itemshortcut.cpp | 2 +- src/net/charserverhandler.cpp | 2 +- src/net/ea/beinghandler.cpp | 12 +- src/net/ea/buysellhandler.cpp | 11 +- src/net/ea/charserverhandler.cpp | 4 +- src/net/ea/chathandler.cpp | 4 +- src/net/ea/gamehandler.cpp | 2 +- src/net/ea/guildhandler.cpp | 2 +- src/net/ea/inventoryhandler.cpp | 2 +- src/net/ea/inventoryhandler.h | 2 +- src/net/ea/loginhandler.cpp | 2 +- src/net/ea/npchandler.cpp | 2 +- src/net/ea/partyhandler.cpp | 2 +- src/net/ea/playerhandler.cpp | 11 +- src/net/ea/skillhandler.cpp | 2 +- src/net/ea/tradehandler.cpp | 4 +- src/net/eathena/beinghandler.cpp | 7 +- src/net/eathena/buysellhandler.cpp | 2 +- src/net/eathena/generalhandler.cpp | 8 +- src/net/eathena/npchandler.cpp | 2 +- src/net/tmwa/buysellhandler.cpp | 2 +- src/net/tmwa/generalhandler.cpp | 8 +- src/net/tmwa/npchandler.cpp | 3 +- src/net/tmwa/playerhandler.cpp | 2 +- src/net/tmwa/questhandler.cpp | 4 +- src/spellmanager.cpp | 2 +- 237 files changed, 28592 insertions(+), 28544 deletions(-) delete mode 100644 src/gui/botcheckerwindow.cpp delete mode 100644 src/gui/botcheckerwindow.h delete mode 100644 src/gui/buydialog.cpp delete mode 100644 src/gui/buydialog.h delete mode 100644 src/gui/buyselldialog.cpp delete mode 100644 src/gui/buyselldialog.h delete mode 100644 src/gui/changeemaildialog.cpp delete mode 100644 src/gui/changeemaildialog.h delete mode 100644 src/gui/changepassworddialog.cpp delete mode 100644 src/gui/changepassworddialog.h delete mode 100644 src/gui/charcreatedialog.cpp delete mode 100644 src/gui/charcreatedialog.h delete mode 100644 src/gui/charselectdialog.cpp delete mode 100644 src/gui/charselectdialog.h delete mode 100644 src/gui/chatwindow.cpp delete mode 100644 src/gui/chatwindow.h delete mode 100644 src/gui/confirmdialog.cpp delete mode 100644 src/gui/confirmdialog.h delete mode 100644 src/gui/connectiondialog.cpp delete mode 100644 src/gui/connectiondialog.h delete mode 100644 src/gui/debugwindow.cpp delete mode 100644 src/gui/debugwindow.h delete mode 100644 src/gui/didyouknowwindow.cpp delete mode 100644 src/gui/didyouknowwindow.h delete mode 100644 src/gui/editdialog.cpp delete mode 100644 src/gui/editdialog.h delete mode 100644 src/gui/editserverdialog.cpp delete mode 100644 src/gui/editserverdialog.h delete mode 100644 src/gui/emotewindow.cpp delete mode 100644 src/gui/emotewindow.h delete mode 100644 src/gui/equipmentwindow.cpp delete mode 100644 src/gui/equipmentwindow.h delete mode 100644 src/gui/helpwindow.cpp delete mode 100644 src/gui/helpwindow.h delete mode 100644 src/gui/inventorywindow.cpp delete mode 100644 src/gui/inventorywindow.h delete mode 100644 src/gui/itemamountwindow.cpp delete mode 100644 src/gui/itemamountwindow.h delete mode 100644 src/gui/killstats.cpp delete mode 100644 src/gui/killstats.h delete mode 100644 src/gui/logindialog.cpp delete mode 100644 src/gui/logindialog.h delete mode 100644 src/gui/minimap.cpp delete mode 100644 src/gui/minimap.h delete mode 100644 src/gui/ministatuswindow.cpp delete mode 100644 src/gui/ministatuswindow.h delete mode 100644 src/gui/npcdialog.cpp delete mode 100644 src/gui/npcdialog.h delete mode 100644 src/gui/npcpostdialog.cpp delete mode 100644 src/gui/npcpostdialog.h delete mode 100644 src/gui/okdialog.cpp delete mode 100644 src/gui/okdialog.h delete mode 100644 src/gui/outfitwindow.cpp delete mode 100644 src/gui/outfitwindow.h delete mode 100644 src/gui/questswindow.cpp delete mode 100644 src/gui/questswindow.h delete mode 100644 src/gui/quitdialog.cpp delete mode 100644 src/gui/quitdialog.h delete mode 100644 src/gui/registerdialog.cpp delete mode 100644 src/gui/registerdialog.h delete mode 100644 src/gui/selldialog.cpp delete mode 100644 src/gui/selldialog.h delete mode 100644 src/gui/serverdialog.cpp delete mode 100644 src/gui/serverdialog.h delete mode 100644 src/gui/setup.cpp delete mode 100644 src/gui/setup.h delete mode 100644 src/gui/shopwindow.cpp delete mode 100644 src/gui/shopwindow.h delete mode 100644 src/gui/shortcutwindow.cpp delete mode 100644 src/gui/shortcutwindow.h delete mode 100644 src/gui/skilldialog.cpp delete mode 100644 src/gui/skilldialog.h delete mode 100644 src/gui/socialwindow.cpp delete mode 100644 src/gui/socialwindow.h delete mode 100644 src/gui/statuswindow.cpp delete mode 100644 src/gui/statuswindow.h delete mode 100644 src/gui/textcommandeditor.cpp delete mode 100644 src/gui/textcommandeditor.h delete mode 100644 src/gui/textdialog.cpp delete mode 100644 src/gui/textdialog.h delete mode 100644 src/gui/tradewindow.cpp delete mode 100644 src/gui/tradewindow.h delete mode 100644 src/gui/unregisterdialog.cpp delete mode 100644 src/gui/unregisterdialog.h delete mode 100644 src/gui/updaterwindow.cpp delete mode 100644 src/gui/updaterwindow.h delete mode 100644 src/gui/whoisonline.cpp delete mode 100644 src/gui/whoisonline.h create mode 100644 src/gui/windows/botcheckerwindow.cpp create mode 100644 src/gui/windows/botcheckerwindow.h create mode 100644 src/gui/windows/buydialog.cpp create mode 100644 src/gui/windows/buydialog.h create mode 100644 src/gui/windows/buyselldialog.cpp create mode 100644 src/gui/windows/buyselldialog.h create mode 100644 src/gui/windows/changeemaildialog.cpp create mode 100644 src/gui/windows/changeemaildialog.h create mode 100644 src/gui/windows/changepassworddialog.cpp create mode 100644 src/gui/windows/changepassworddialog.h create mode 100644 src/gui/windows/charcreatedialog.cpp create mode 100644 src/gui/windows/charcreatedialog.h create mode 100644 src/gui/windows/charselectdialog.cpp create mode 100644 src/gui/windows/charselectdialog.h create mode 100644 src/gui/windows/chatwindow.cpp create mode 100644 src/gui/windows/chatwindow.h create mode 100644 src/gui/windows/confirmdialog.cpp create mode 100644 src/gui/windows/confirmdialog.h create mode 100644 src/gui/windows/connectiondialog.cpp create mode 100644 src/gui/windows/connectiondialog.h create mode 100644 src/gui/windows/debugwindow.cpp create mode 100644 src/gui/windows/debugwindow.h create mode 100644 src/gui/windows/didyouknowwindow.cpp create mode 100644 src/gui/windows/didyouknowwindow.h create mode 100644 src/gui/windows/editdialog.cpp create mode 100644 src/gui/windows/editdialog.h create mode 100644 src/gui/windows/editserverdialog.cpp create mode 100644 src/gui/windows/editserverdialog.h create mode 100644 src/gui/windows/emotewindow.cpp create mode 100644 src/gui/windows/emotewindow.h create mode 100644 src/gui/windows/equipmentwindow.cpp create mode 100644 src/gui/windows/equipmentwindow.h create mode 100644 src/gui/windows/helpwindow.cpp create mode 100644 src/gui/windows/helpwindow.h create mode 100644 src/gui/windows/inventorywindow.cpp create mode 100644 src/gui/windows/inventorywindow.h create mode 100644 src/gui/windows/itemamountwindow.cpp create mode 100644 src/gui/windows/itemamountwindow.h create mode 100644 src/gui/windows/killstats.cpp create mode 100644 src/gui/windows/killstats.h create mode 100644 src/gui/windows/logindialog.cpp create mode 100644 src/gui/windows/logindialog.h create mode 100644 src/gui/windows/minimap.cpp create mode 100644 src/gui/windows/minimap.h create mode 100644 src/gui/windows/ministatuswindow.cpp create mode 100644 src/gui/windows/ministatuswindow.h create mode 100644 src/gui/windows/npcdialog.cpp create mode 100644 src/gui/windows/npcdialog.h create mode 100644 src/gui/windows/npcpostdialog.cpp create mode 100644 src/gui/windows/npcpostdialog.h create mode 100644 src/gui/windows/okdialog.cpp create mode 100644 src/gui/windows/okdialog.h create mode 100644 src/gui/windows/outfitwindow.cpp create mode 100644 src/gui/windows/outfitwindow.h create mode 100644 src/gui/windows/questswindow.cpp create mode 100644 src/gui/windows/questswindow.h create mode 100644 src/gui/windows/quitdialog.cpp create mode 100644 src/gui/windows/quitdialog.h create mode 100644 src/gui/windows/registerdialog.cpp create mode 100644 src/gui/windows/registerdialog.h create mode 100644 src/gui/windows/selldialog.cpp create mode 100644 src/gui/windows/selldialog.h create mode 100644 src/gui/windows/serverdialog.cpp create mode 100644 src/gui/windows/serverdialog.h create mode 100644 src/gui/windows/setup.cpp create mode 100644 src/gui/windows/setup.h create mode 100644 src/gui/windows/shopwindow.cpp create mode 100644 src/gui/windows/shopwindow.h create mode 100644 src/gui/windows/shortcutwindow.cpp create mode 100644 src/gui/windows/shortcutwindow.h create mode 100644 src/gui/windows/skilldialog.cpp create mode 100644 src/gui/windows/skilldialog.h create mode 100644 src/gui/windows/socialwindow.cpp create mode 100644 src/gui/windows/socialwindow.h create mode 100644 src/gui/windows/statuswindow.cpp create mode 100644 src/gui/windows/statuswindow.h create mode 100644 src/gui/windows/textcommandeditor.cpp create mode 100644 src/gui/windows/textcommandeditor.h create mode 100644 src/gui/windows/textdialog.cpp create mode 100644 src/gui/windows/textdialog.h create mode 100644 src/gui/windows/tradewindow.cpp create mode 100644 src/gui/windows/tradewindow.h create mode 100644 src/gui/windows/unregisterdialog.cpp create mode 100644 src/gui/windows/unregisterdialog.h create mode 100644 src/gui/windows/updaterwindow.cpp create mode 100644 src/gui/windows/updaterwindow.h create mode 100644 src/gui/windows/whoisonline.cpp create mode 100644 src/gui/windows/whoisonline.h create mode 100644 src/gui/windows/worldselectdialog.cpp create mode 100644 src/gui/windows/worldselectdialog.h delete mode 100644 src/gui/worldselectdialog.cpp delete mode 100644 src/gui/worldselectdialog.h diff --git a/Android.mk b/Android.mk index 3e2e0d39b..5bac92b93 100644 --- a/Android.mk +++ b/Android.mk @@ -33,6 +33,7 @@ LOCAL_SRC_FILES := $(SDL_PATH)/src/main/android/SDL_android_main.c \ $(wildcard $(LOCAL_PATH)/src/being/*.cpp) \ $(wildcard $(LOCAL_PATH)/src/gui/*.cpp) \ $(wildcard $(LOCAL_PATH)/src/gui/widgets/*.cpp) \ + $(wildcard $(LOCAL_PATH)/src/gui/windows/*.cpp) \ $(wildcard $(LOCAL_PATH)/src/guichan/*.cpp) \ $(wildcard $(LOCAL_PATH)/src/guichan/widgets/*.cpp) \ $(wildcard $(LOCAL_PATH)/src/input/*.cpp) \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2c33d96c0..e2acfb4dc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -253,90 +253,90 @@ SET(SRCS gui/widgets/windowcontainer.h gui/beingpopup.cpp gui/beingpopup.h - gui/buydialog.cpp - gui/buydialog.h - gui/buyselldialog.cpp - gui/buyselldialog.h - gui/changeemaildialog.cpp - gui/changeemaildialog.h - gui/changepassworddialog.cpp - gui/changepassworddialog.h - gui/charselectdialog.cpp - gui/charselectdialog.h - gui/charcreatedialog.cpp - gui/charcreatedialog.h - gui/chatwindow.cpp - gui/chatwindow.h - gui/confirmdialog.cpp - gui/confirmdialog.h - gui/connectiondialog.cpp - gui/connectiondialog.h - gui/debugwindow.cpp - gui/debugwindow.h - gui/didyouknowwindow.cpp - gui/didyouknowwindow.h - gui/editserverdialog.cpp - gui/editserverdialog.h - gui/emotewindow.cpp - gui/emotewindow.h - gui/equipmentwindow.cpp - gui/equipmentwindow.h + gui/windows/buydialog.cpp + gui/windows/buydialog.h + gui/windows/buyselldialog.cpp + gui/windows/buyselldialog.h + gui/windows/changeemaildialog.cpp + gui/windows/changeemaildialog.h + gui/windows/changepassworddialog.cpp + gui/windows/changepassworddialog.h + gui/windows/charselectdialog.cpp + gui/windows/charselectdialog.h + gui/windows/charcreatedialog.cpp + gui/windows/charcreatedialog.h + gui/windows/chatwindow.cpp + gui/windows/chatwindow.h + gui/windows/confirmdialog.cpp + gui/windows/confirmdialog.h + gui/windows/connectiondialog.cpp + gui/windows/connectiondialog.h + gui/windows/debugwindow.cpp + gui/windows/debugwindow.h + gui/windows/didyouknowwindow.cpp + gui/windows/didyouknowwindow.h + gui/windows/editdialog.cpp + gui/windows/editdialog.h + gui/windows/editserverdialog.cpp + gui/windows/editserverdialog.h + gui/windows/emotewindow.cpp + gui/windows/emotewindow.h + gui/windows/equipmentwindow.cpp + gui/windows/equipmentwindow.h gui/focushandler.cpp gui/focushandler.h gui/gui.cpp gui/gui.h - gui/helpwindow.cpp - gui/helpwindow.h - gui/inventorywindow.cpp - gui/inventorywindow.h + gui/windows/helpwindow.cpp + gui/windows/helpwindow.h + gui/windows/inventorywindow.cpp + gui/windows/inventorywindow.h + gui/windows/itemamountwindow.cpp + gui/windows/itemamountwindow.h gui/itempopup.cpp gui/itempopup.h gui/spellpopup.cpp gui/spellpopup.h gui/statuspopup.cpp gui/statuspopup.h - gui/killstats.cpp - gui/killstats.h - gui/itemamountwindow.cpp - gui/itemamountwindow.h - gui/logindialog.cpp - gui/logindialog.h - gui/minimap.cpp - gui/minimap.h - gui/ministatuswindow.cpp - gui/ministatuswindow.h - gui/npcdialog.cpp - gui/npcdialog.h - gui/npcpostdialog.cpp - gui/npcpostdialog.h - gui/okdialog.cpp - gui/okdialog.h - gui/editdialog.cpp - gui/editdialog.h - gui/outfitwindow.cpp - gui/outfitwindow.h - gui/botcheckerwindow.cpp - gui/botcheckerwindow.h - gui/textcommandeditor.cpp - gui/textcommandeditor.h + gui/windows/killstats.cpp + gui/windows/killstats.h + gui/windows/logindialog.cpp + gui/windows/logindialog.h + gui/windows/minimap.cpp + gui/windows/minimap.h + gui/windows/ministatuswindow.cpp + gui/windows/ministatuswindow.h + gui/windows/npcdialog.cpp + gui/windows/npcdialog.h + gui/windows/npcpostdialog.cpp + gui/windows/npcpostdialog.h + gui/windows/okdialog.cpp + gui/windows/okdialog.h + gui/windows/outfitwindow.cpp + gui/windows/outfitwindow.h + gui/windows/botcheckerwindow.cpp + gui/windows/botcheckerwindow.h + gui/windows/textcommandeditor.cpp + gui/windows/textcommandeditor.h gui/palette.cpp gui/palette.h gui/popupmenu.cpp gui/popupmenu.h - gui/questswindow.cpp - gui/questswindow.h - gui/quitdialog.cpp - gui/quitdialog.h - gui/registerdialog.cpp - gui/registerdialog.h + gui/windows/questswindow.cpp + gui/windows/questswindow.h + gui/windows/quitdialog.cpp + gui/windows/quitdialog.h + gui/windows/registerdialog.cpp + gui/windows/registerdialog.h gui/sdlinput.cpp gui/sdlinput.h - gui/selldialog.cpp - gui/selldialog.h - gui/serverdialog.cpp - gui/serverdialog.h - gui/setup.cpp - gui/setup.h + gui/windows/selldialog.cpp + gui/windows/selldialog.h + gui/windows/serverdialog.cpp + gui/windows/serverdialog.h + gui/windows/setup.cpp + gui/windows/setup.h gui/setup_audio.cpp gui/setup_audio.h gui/setup_colors.cpp @@ -366,40 +366,40 @@ SET(SRCS gui/setupactiondata.h gui/sdlfont.cpp gui/sdlfont.h - gui/shopwindow.cpp - gui/shopwindow.h - gui/shortcutwindow.cpp - gui/shortcutwindow.h - gui/skilldialog.cpp - gui/skilldialog.h - gui/socialwindow.cpp - gui/socialwindow.h + gui/windows/shopwindow.cpp + gui/windows/shopwindow.h + gui/windows/shortcutwindow.cpp + gui/windows/shortcutwindow.h + gui/windows/skilldialog.cpp + gui/windows/skilldialog.h + gui/windows/socialwindow.cpp + gui/windows/socialwindow.h gui/speechbubble.cpp gui/speechbubble.h - gui/statuswindow.cpp - gui/statuswindow.h - gui/textdialog.cpp - gui/textdialog.h + gui/windows/statuswindow.cpp + gui/windows/statuswindow.h + gui/windows/textdialog.cpp + gui/windows/textdialog.h gui/textpopup.cpp gui/textpopup.h gui/theme.cpp gui/theme.h - gui/tradewindow.cpp - gui/tradewindow.h - gui/unregisterdialog.cpp - gui/unregisterdialog.h - gui/updaterwindow.cpp - gui/updaterwindow.h + gui/windows/tradewindow.cpp + gui/windows/tradewindow.h + gui/windows/unregisterdialog.cpp + gui/windows/unregisterdialog.h + gui/windows/updaterwindow.cpp + gui/windows/updaterwindow.h gui/userpalette.cpp gui/userpalette.h gui/viewport.cpp gui/viewport.h - gui/whoisonline.cpp - gui/whoisonline.h + gui/windows/whoisonline.cpp + gui/windows/whoisonline.h gui/windowmenu.cpp gui/windowmenu.h - gui/worldselectdialog.cpp - gui/worldselectdialog.h + gui/windows/worldselectdialog.cpp + gui/windows/worldselectdialog.h net/adminhandler.h net/charserverhandler.cpp net/charserverhandler.h diff --git a/src/Makefile.am b/src/Makefile.am index 710031fa1..b23baeaca 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -262,90 +262,90 @@ manaplus_SOURCES += gui/widgets/avatarlistbox.cpp \ gui/widgets/windowcontainer.h \ gui/beingpopup.cpp \ gui/beingpopup.h \ - gui/buydialog.cpp \ - gui/buydialog.h \ - gui/buyselldialog.cpp \ - gui/buyselldialog.h \ - gui/changeemaildialog.cpp \ - gui/changeemaildialog.h \ - gui/changepassworddialog.cpp \ - gui/changepassworddialog.h \ - gui/charselectdialog.cpp \ - gui/charselectdialog.h \ - gui/charcreatedialog.cpp \ - gui/charcreatedialog.h \ - gui/chatwindow.cpp \ - gui/chatwindow.h \ - gui/confirmdialog.cpp \ - gui/confirmdialog.h \ - gui/connectiondialog.cpp \ - gui/connectiondialog.h \ - gui/debugwindow.cpp \ - gui/debugwindow.h \ - gui/didyouknowwindow.cpp \ - gui/didyouknowwindow.h \ - gui/editserverdialog.cpp \ - gui/editserverdialog.h \ - gui/emotewindow.cpp \ - gui/emotewindow.h \ - gui/equipmentwindow.cpp \ - gui/equipmentwindow.h \ + gui/windows/buydialog.cpp \ + gui/windows/buydialog.h \ + gui/windows/buyselldialog.cpp \ + gui/windows/buyselldialog.h \ + gui/windows/changeemaildialog.cpp \ + gui/windows/changeemaildialog.h \ + gui/windows/changepassworddialog.cpp \ + gui/windows/changepassworddialog.h \ + gui/windows/charselectdialog.cpp \ + gui/windows/charselectdialog.h \ + gui/windows/charcreatedialog.cpp \ + gui/windows/charcreatedialog.h \ + gui/windows/chatwindow.cpp \ + gui/windows/chatwindow.h \ + gui/windows/confirmdialog.cpp \ + gui/windows/confirmdialog.h \ + gui/windows/connectiondialog.cpp \ + gui/windows/connectiondialog.h \ + gui/windows/debugwindow.cpp \ + gui/windows/debugwindow.h \ + gui/windows/didyouknowwindow.cpp \ + gui/windows/didyouknowwindow.h \ + gui/windows/editdialog.cpp \ + gui/windows/editdialog.h \ + gui/windows/editserverdialog.cpp \ + gui/windows/editserverdialog.h \ + gui/windows/emotewindow.cpp \ + gui/windows/emotewindow.h \ + gui/windows/equipmentwindow.cpp \ + gui/windows/equipmentwindow.h \ gui/focushandler.cpp \ gui/focushandler.h \ gui/gui.cpp \ gui/gui.h \ - gui/helpwindow.cpp \ - gui/helpwindow.h \ - gui/inventorywindow.cpp \ - gui/inventorywindow.h \ - gui/itemamountwindow.cpp \ - gui/itemamountwindow.h \ + gui/windows/helpwindow.cpp \ + gui/windows/helpwindow.h \ + gui/windows/inventorywindow.cpp \ + gui/windows/inventorywindow.h \ + gui/windows/itemamountwindow.cpp \ + gui/windows/itemamountwindow.h \ gui/itempopup.cpp \ gui/itempopup.h \ gui/spellpopup.cpp \ gui/spellpopup.h \ gui/statuspopup.cpp \ gui/statuspopup.h \ - gui/killstats.cpp \ - gui/killstats.h \ - gui/logindialog.cpp \ - gui/logindialog.h \ - gui/minimap.cpp \ - gui/minimap.h \ - gui/ministatuswindow.cpp \ - gui/ministatuswindow.h \ - gui/npcdialog.cpp \ - gui/npcdialog.h \ - gui/npcpostdialog.cpp \ - gui/npcpostdialog.h \ - gui/okdialog.cpp \ - gui/okdialog.h \ - gui/editdialog.cpp \ - gui/editdialog.h \ - gui/outfitwindow.cpp \ - gui/outfitwindow.h \ - gui/botcheckerwindow.cpp \ - gui/botcheckerwindow.h \ - gui/textcommandeditor.cpp \ - gui/textcommandeditor.h \ + gui/windows/killstats.cpp \ + gui/windows/killstats.h \ + gui/windows/logindialog.cpp \ + gui/windows/logindialog.h \ + gui/windows/minimap.cpp \ + gui/windows/minimap.h \ + gui/windows/ministatuswindow.cpp \ + gui/windows/ministatuswindow.h \ + gui/windows/npcdialog.cpp \ + gui/windows/npcdialog.h \ + gui/windows/npcpostdialog.cpp \ + gui/windows/npcpostdialog.h \ + gui/windows/okdialog.cpp \ + gui/windows/okdialog.h \ + gui/windows/outfitwindow.cpp \ + gui/windows/outfitwindow.h \ + gui/windows/botcheckerwindow.cpp \ + gui/windows/botcheckerwindow.h \ + gui/windows/textcommandeditor.cpp \ + gui/windows/textcommandeditor.h \ gui/palette.cpp \ gui/palette.h \ gui/popupmenu.cpp \ gui/popupmenu.h \ - gui/questswindow.cpp \ - gui/questswindow.h \ - gui/quitdialog.cpp \ - gui/quitdialog.h \ - gui/registerdialog.cpp \ - gui/registerdialog.h \ + gui/windows/questswindow.cpp \ + gui/windows/questswindow.h \ + gui/windows/quitdialog.cpp \ + gui/windows/quitdialog.h \ + gui/windows/registerdialog.cpp \ + gui/windows/registerdialog.h \ gui/sdlinput.cpp \ gui/sdlinput.h \ - gui/selldialog.cpp \ - gui/selldialog.h \ - gui/serverdialog.cpp \ - gui/serverdialog.h \ - gui/setup.cpp \ - gui/setup.h \ + gui/windows/selldialog.cpp \ + gui/windows/selldialog.h \ + gui/windows/serverdialog.cpp \ + gui/windows/serverdialog.h \ + gui/windows/setup.cpp \ + gui/windows/setup.h \ gui/setup_audio.cpp \ gui/setup_audio.h \ gui/setup_colors.cpp \ @@ -375,40 +375,40 @@ manaplus_SOURCES += gui/widgets/avatarlistbox.cpp \ gui/setupactiondata.h \ gui/sdlfont.cpp \ gui/sdlfont.h \ - gui/shopwindow.cpp \ - gui/shopwindow.h \ - gui/shortcutwindow.cpp \ - gui/shortcutwindow.h \ - gui/skilldialog.cpp \ - gui/skilldialog.h \ - gui/socialwindow.cpp \ - gui/socialwindow.h \ + gui/windows/shopwindow.cpp \ + gui/windows/shopwindow.h \ + gui/windows/shortcutwindow.cpp \ + gui/windows/shortcutwindow.h \ + gui/windows/skilldialog.cpp \ + gui/windows/skilldialog.h \ + gui/windows/socialwindow.cpp \ + gui/windows/socialwindow.h \ gui/speechbubble.cpp \ gui/speechbubble.h \ - gui/statuswindow.cpp \ - gui/statuswindow.h \ - gui/textdialog.cpp \ - gui/textdialog.h \ + gui/windows/statuswindow.cpp \ + gui/windows/statuswindow.h \ + gui/windows/textdialog.cpp \ + gui/windows/textdialog.h \ gui/textpopup.cpp \ gui/textpopup.h \ gui/theme.cpp \ gui/theme.h \ - gui/tradewindow.cpp \ - gui/tradewindow.h \ - gui/unregisterdialog.cpp \ - gui/unregisterdialog.h \ - gui/updaterwindow.cpp \ - gui/updaterwindow.h \ + gui/windows/tradewindow.cpp \ + gui/windows/tradewindow.h \ + gui/windows/unregisterdialog.cpp \ + gui/windows/unregisterdialog.h \ + gui/windows/updaterwindow.cpp \ + gui/windows/updaterwindow.h \ gui/userpalette.cpp \ gui/userpalette.h \ gui/viewport.cpp \ gui/viewport.h \ - gui/whoisonline.cpp \ - gui/whoisonline.h \ + gui/windows/whoisonline.cpp \ + gui/windows/whoisonline.h \ gui/windowmenu.cpp \ gui/windowmenu.h \ - gui/worldselectdialog.cpp \ - gui/worldselectdialog.h \ + gui/windows/worldselectdialog.cpp \ + gui/windows/worldselectdialog.h \ net/adminhandler.h \ net/beinghandler.h \ net/buysellhandler.h \ diff --git a/src/actionmanager.cpp b/src/actionmanager.cpp index eb2501b53..a675c6d42 100644 --- a/src/actionmanager.cpp +++ b/src/actionmanager.cpp @@ -34,29 +34,31 @@ #include "input/inputevent.h" #include "input/inputmanager.h" -#include "gui/botcheckerwindow.h" -#include "gui/buyselldialog.h" -#include "gui/chatwindow.h" -#include "gui/debugwindow.h" -#include "gui/didyouknowwindow.h" -#include "gui/equipmentwindow.h" -#include "gui/helpwindow.h" -#include "gui/inventorywindow.h" -#include "gui/killstats.h" -#include "gui/minimap.h" -#include "gui/ministatuswindow.h" -#include "gui/npcdialog.h" -#include "gui/outfitwindow.h" -#include "gui/setup.h" -#include "gui/shopwindow.h" -#include "gui/shortcutwindow.h" -#include "gui/skilldialog.h" -#include "gui/socialwindow.h" -#include "gui/statuswindow.h" #include "gui/viewport.h" -#include "gui/questswindow.h" -#include "gui/quitdialog.h" -#include "gui/whoisonline.h" + +#include "gui/windows/skilldialog.h" +#include "gui/windows/socialwindow.h" +#include "gui/windows/statuswindow.h" +#include "gui/windows/questswindow.h" +#include "gui/windows/quitdialog.h" +#include "gui/windows/whoisonline.h" + +#include "gui/windows/botcheckerwindow.h" +#include "gui/windows/buyselldialog.h" +#include "gui/windows/chatwindow.h" +#include "gui/windows/debugwindow.h" +#include "gui/windows/didyouknowwindow.h" +#include "gui/windows/equipmentwindow.h" +#include "gui/windows/helpwindow.h" +#include "gui/windows/inventorywindow.h" +#include "gui/windows/killstats.h" +#include "gui/windows/minimap.h" +#include "gui/windows/ministatuswindow.h" +#include "gui/windows/npcdialog.h" +#include "gui/windows/outfitwindow.h" +#include "gui/windows/setup.h" +#include "gui/windows/shopwindow.h" +#include "gui/windows/shortcutwindow.h" #include "gui/widgets/chattab.h" diff --git a/src/actorspritemanager.cpp b/src/actorspritemanager.cpp index f4446cb85..2996d7167 100644 --- a/src/actorspritemanager.cpp +++ b/src/actorspritemanager.cpp @@ -30,12 +30,12 @@ #include "being/playerinfo.h" #include "being/playerrelations.h" -#include "gui/chatwindow.h" -#include "gui/equipmentwindow.h" -#include "gui/socialwindow.h" #include "gui/viewport.h" #include "gui/widgets/chattab.h" +#include "gui/windows/chatwindow.h" +#include "gui/windows/equipmentwindow.h" +#include "gui/windows/socialwindow.h" #include "utils/checkutils.h" #include "utils/gettext.h" diff --git a/src/being/being.cpp b/src/being/being.cpp index 949a691c1..07cac90c1 100644 --- a/src/being/being.cpp +++ b/src/being/being.cpp @@ -38,11 +38,12 @@ #include "particle/particle.h" -#include "gui/equipmentwindow.h" -#include "gui/socialwindow.h" #include "gui/speechbubble.h" #include "gui/sdlfont.h" -#include "gui/skilldialog.h" + +#include "gui/windows/equipmentwindow.h" +#include "gui/windows/skilldialog.h" +#include "gui/windows/socialwindow.h" #include "net/charserverhandler.h" #include "net/gamehandler.h" diff --git a/src/being/localplayer.cpp b/src/being/localplayer.cpp index f8a13f8a0..2c7724d26 100644 --- a/src/being/localplayer.cpp +++ b/src/being/localplayer.cpp @@ -42,18 +42,19 @@ #include "input/keyboardconfig.h" -#include "gui/chatwindow.h" #include "gui/gui.h" -#include "gui/ministatuswindow.h" -#include "gui/okdialog.h" -#include "gui/outfitwindow.h" -#include "gui/shopwindow.h" #include "gui/sdlfont.h" -#include "gui/skilldialog.h" -#include "gui/socialwindow.h" -#include "gui/updaterwindow.h" #include "gui/viewport.h" +#include "gui/windows/chatwindow.h" +#include "gui/windows/ministatuswindow.h" +#include "gui/windows/okdialog.h" +#include "gui/windows/outfitwindow.h" +#include "gui/windows/shopwindow.h" +#include "gui/windows/skilldialog.h" +#include "gui/windows/socialwindow.h" +#include "gui/windows/updaterwindow.h" + #include "gui/widgets/gmtab.h" #include "gui/widgets/whispertab.h" diff --git a/src/being/playerinfo.cpp b/src/being/playerinfo.cpp index 5b94c0018..be9087b77 100644 --- a/src/being/playerinfo.cpp +++ b/src/being/playerinfo.cpp @@ -26,9 +26,9 @@ #include "depricatedevent.h" #include "inventory.h" -#include "gui/inventorywindow.h" -#include "gui/npcdialog.h" -#include "gui/npcpostdialog.h" +#include "gui/windows/inventorywindow.h" +#include "gui/windows/npcdialog.h" +#include "gui/windows/npcpostdialog.h" #include "resources/iteminfo.h" diff --git a/src/client.cpp b/src/client.cpp index a14e36198..fb58c313a 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -47,28 +47,29 @@ #include "input/joystick.h" #include "input/keyboardconfig.h" -#include "gui/buydialog.h" -#include "gui/buyselldialog.h" -#include "gui/changeemaildialog.h" -#include "gui/changepassworddialog.h" -#include "gui/charselectdialog.h" -#include "gui/confirmdialog.h" -#include "gui/connectiondialog.h" -#include "gui/didyouknowwindow.h" #include "gui/gui.h" -#include "gui/helpwindow.h" -#include "gui/logindialog.h" -#include "gui/okdialog.h" -#include "gui/quitdialog.h" -#include "gui/registerdialog.h" -#include "gui/npcdialog.h" -#include "gui/selldialog.h" -#include "gui/serverdialog.h" -#include "gui/setup.h" #include "gui/theme.h" -#include "gui/unregisterdialog.h" -#include "gui/updaterwindow.h" -#include "gui/worldselectdialog.h" + +#include "gui/windows/buyselldialog.h" +#include "gui/windows/buydialog.h" +#include "gui/windows/changeemaildialog.h" +#include "gui/windows/changepassworddialog.h" +#include "gui/windows/charselectdialog.h" +#include "gui/windows/confirmdialog.h" +#include "gui/windows/connectiondialog.h" +#include "gui/windows/didyouknowwindow.h" +#include "gui/windows/helpwindow.h" +#include "gui/windows/logindialog.h" +#include "gui/windows/npcdialog.h" +#include "gui/windows/okdialog.h" +#include "gui/windows/registerdialog.h" +#include "gui/windows/selldialog.h" +#include "gui/windows/serverdialog.h" +#include "gui/windows/setup.h" +#include "gui/windows/unregisterdialog.h" +#include "gui/windows/updaterwindow.h" +#include "gui/windows/quitdialog.h" +#include "gui/windows/worldselectdialog.h" #include "gui/widgets/button.h" #include "gui/widgets/desktop.h" diff --git a/src/commands.cpp b/src/commands.cpp index fc033cd83..522aabcb3 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -34,14 +34,15 @@ #include "being/localplayer.h" #include "being/playerrelations.h" -#include "gui/buydialog.h" -#include "gui/chatwindow.h" -#include "gui/helpwindow.h" #include "gui/gui.h" -#include "gui/outfitwindow.h" -#include "gui/shopwindow.h" -#include "gui/socialwindow.h" -#include "gui/tradewindow.h" + +#include "gui/windows/buydialog.h" +#include "gui/windows/chatwindow.h" +#include "gui/windows/helpwindow.h" +#include "gui/windows/outfitwindow.h" +#include "gui/windows/shopwindow.h" +#include "gui/windows/socialwindow.h" +#include "gui/windows/tradewindow.h" #include "gui/widgets/whispertab.h" diff --git a/src/game.cpp b/src/game.cpp index 6bae44e49..2cd541acb 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -47,33 +47,34 @@ #include "input/joystick.h" #include "input/keyboardconfig.h" -#include "gui/botcheckerwindow.h" -#include "gui/debugwindow.h" -#include "gui/didyouknowwindow.h" -#include "gui/emotewindow.h" -#include "gui/equipmentwindow.h" #include "gui/gui.h" -#include "gui/helpwindow.h" -#include "gui/inventorywindow.h" -#include "gui/killstats.h" -#include "gui/minimap.h" -#include "gui/ministatuswindow.h" -#include "gui/okdialog.h" -#include "gui/outfitwindow.h" -#include "gui/setup.h" -#include "gui/shopwindow.h" -#include "gui/shortcutwindow.h" -#include "gui/socialwindow.h" #ifdef MANASERV_SUPPORT #include "gui/specialswindow.h" #endif -#include "gui/skilldialog.h" -#include "gui/statuswindow.h" -#include "gui/tradewindow.h" #include "gui/viewport.h" -#include "gui/questswindow.h" #include "gui/windowmenu.h" -#include "gui/whoisonline.h" + +#include "gui/windows/botcheckerwindow.h" +#include "gui/windows/debugwindow.h" +#include "gui/windows/didyouknowwindow.h" +#include "gui/windows/emotewindow.h" +#include "gui/windows/equipmentwindow.h" +#include "gui/windows/helpwindow.h" +#include "gui/windows/inventorywindow.h" +#include "gui/windows/killstats.h" +#include "gui/windows/minimap.h" +#include "gui/windows/ministatuswindow.h" +#include "gui/windows/okdialog.h" +#include "gui/windows/outfitwindow.h" +#include "gui/windows/setup.h" +#include "gui/windows/shopwindow.h" +#include "gui/windows/shortcutwindow.h" +#include "gui/windows/skilldialog.h" +#include "gui/windows/socialwindow.h" +#include "gui/windows/statuswindow.h" +#include "gui/windows/tradewindow.h" +#include "gui/windows/questswindow.h" +#include "gui/windows/whoisonline.h" #include "gui/widgets/battletab.h" #include "gui/widgets/dropshortcutcontainer.h" diff --git a/src/gui/botcheckerwindow.cpp b/src/gui/botcheckerwindow.cpp deleted file mode 100644 index 58321b12f..000000000 --- a/src/gui/botcheckerwindow.cpp +++ /dev/null @@ -1,421 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 Andrei Karas - * Copyright (C) 2011-2013 The ManaPlus developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/botcheckerwindow.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/scrollarea.h" -#include "gui/widgets/label.h" -#include "gui/widgets/guitable.h" - -#include "actorspritemanager.h" -#include "configuration.h" - -#include "being/localplayer.h" - -#include "utils/gettext.h" - -#include - -#include "debug.h" - -const int COLUMNS_NR = 5; // name plus listbox -const int NAME_COLUMN = 0; -const int TIME_COLUMN = 1; - -const int ROW_HEIGHT = 12; -// The following column widths really shouldn't be hardcoded but should -// scale with the size of the widget... excep -// that, right now, the widget doesn't exactly scale either. -const int NAME_COLUMN_WIDTH = 185; -const int TIME_COLUMN_WIDTH = 70; - -#define WIDGET_AT(row, column) (((row) * COLUMNS_NR) + column) - -class UsersTableModel final : public TableModel, - public Widget2 -{ -public: - explicit UsersTableModel(const Widget2 *const widget) : - TableModel(), - Widget2(widget), - mPlayers(0), - mWidgets() - { - playersUpdated(); - } - - A_DELETE_COPY(UsersTableModel) - - ~UsersTableModel() - { - freeWidgets(); - } - - int getRows() const - { - return static_cast(mPlayers.size()); - } - - int getColumns() const - { - return COLUMNS_NR; - } - - int getRowHeight() const - { - return ROW_HEIGHT; - } - - int getColumnWidth(const int index) const - { - if (index == NAME_COLUMN) - return NAME_COLUMN_WIDTH; - else - return TIME_COLUMN_WIDTH; - } - - void playersUpdated() - { - signalBeforeUpdate(); - - freeWidgets(); - mPlayers.clear(); - if (actorSpriteManager && botCheckerWindow - && botCheckerWindow->mEnabled) - { - std::set beings = actorSpriteManager->getAll(); - FOR_EACH (ActorSprites::const_iterator, i, beings) - { - Being *const being = dynamic_cast(*i); - - if (being && being->getType() == Being::PLAYER - && being != player_node && being->getName() != "") - { - mPlayers.push_back(being); - } - } - } - - const unsigned int curTime = cur_time; - const unsigned int sz = mPlayers.size(); - // set up widgets - for (unsigned int r = 0; r < sz; ++r) - { - if (!mPlayers.at(r)) - continue; - - const Being *const player = mPlayers.at(r); - gcn::Widget *widget = new Label(this, player->getName()); - - mWidgets.push_back(widget); - - if (player->getAttackTime() != 0) - { - widget = new Label(this, toString(curTime - - player->getAttackTime())); - } - else - { - widget = new Label(this, toString(curTime - - player->getTestTime()).append("?")); - } - mWidgets.push_back(widget); - - if (player->getTalkTime() != 0) - { - widget = new Label(this, toString(curTime - - player->getTalkTime())); - } - else - { - widget = new Label(this, toString(curTime - - player->getTestTime()).append("?")); - } - mWidgets.push_back(widget); - - if (player->getMoveTime() != 0) - { - widget = new Label(this, toString(curTime - - player->getMoveTime())); - } - else - { - widget = new Label(this, toString(curTime - - player->getTestTime()).append("?")); - } - mWidgets.push_back(widget); - - std::string str; - bool talkBot = false; - bool moveBot = false; - bool attackBot = false; - bool otherBot = false; - - if (curTime - player->getTestTime() > 2 * 60) - { - const int attack = curTime - (player->getAttackTime() - ? player->getAttackTime() - : player->getTestTime()); - const int talk = curTime - (player->getTalkTime() - ? player->getTalkTime() - : player->getTestTime()) - attack; - const int move = curTime - (player->getMoveTime() - ? player->getMoveTime() - : player->getTestTime()) - attack; - const int other = curTime - (player->getOtherTime() - ? player->getMoveTime() - : player->getOtherTime()) - attack; - - if (attack < 2 * 60) - attackBot = true; - - // attacking but not talking more than 2 minutes - if (talk > 2 * 60) - { - talkBot = true; - str.append(toString((talk) / 60)).append(" "); - } - - // attacking but not moving more than 2 minutes - if (move > 2 * 60) - { - moveBot = true; - str.append(toString((move) / 60)); - } - - // attacking but not other activity more than 2 minutes - if (move > 2 * 60 && other > 2 * 60) - otherBot = true; - } - - if (str.length() > 0) - { - if (attackBot && talkBot && moveBot && otherBot) - str = "bot!! " + str; - else if (attackBot && talkBot && moveBot) - str = "bot! " + str; - else if (talkBot && moveBot) - str = "bot " + str; - else if (talkBot || moveBot) - str = "bot? " + str; - } - else - { - str = "ok"; - } - - widget = new Label(this, str); - mWidgets.push_back(widget); - } - - signalAfterUpdate(); - } - - void updateModelInRow(const int row A_UNUSED) const - { - } - - gcn::Widget *getElementAt(const int row, const int column) const - { - return mWidgets[WIDGET_AT(row, column)]; - } - - void freeWidgets() - { - for (std::vector::const_iterator it = mWidgets.begin(); - it != mWidgets.end(); ++it) - { - delete *it; - } - - mWidgets.clear(); - } - -protected: - std::vector mPlayers; - std::vector mWidgets; -}; - - -BotCheckerWindow::BotCheckerWindow(): - // TRANSLATORS: bot checker window header - Window(_("Bot Checker"), false, nullptr, "botchecker.xml"), - gcn::ActionListener(), - mTableModel(new UsersTableModel(this)), - mTable(new GuiTable(this, mTableModel)), - playersScrollArea(new ScrollArea(mTable, true, - "bochecker_background.xml")), - mPlayerTableTitleModel(new StaticTableModel(1, COLUMNS_NR)), - mPlayerTitleTable(new GuiTable(this, mPlayerTableTitleModel)), - // TRANSLATORS: bot checker window button - mIncButton(new Button(this, _("Reset"), "reset", this)), - mLastUpdateTime(0), - mNeedUpdate(false), - mEnabled(false) -{ - const int w = 500; - const int h = 250; - - setSaveVisible(true); - - mTable->setOpaque(false); - mTable->setLinewiseSelection(true); - mTable->setWrappingEnabled(true); - mTable->setActionEventId("skill"); - mTable->addActionListener(this); - - mPlayerTableTitleModel->fixColumnWidth(NAME_COLUMN, NAME_COLUMN_WIDTH); - - for (int f = 0; f < 4; f++) - { - mPlayerTableTitleModel->fixColumnWidth( - TIME_COLUMN + f, TIME_COLUMN_WIDTH); - } - - mPlayerTitleTable->setHeight(1); - - // TRANSLATORS: bot checker window table header - mPlayerTableTitleModel->set(0, 0, new Label(this, _("Name"))); - // TRANSLATORS: bot checker window table header - mPlayerTableTitleModel->set(0, 1, new Label(this, _("Attack"))); - // TRANSLATORS: bot checker window table header - mPlayerTableTitleModel->set(0, 2, new Label(this, _("Talk"))); - // TRANSLATORS: bot checker window table header - mPlayerTableTitleModel->set(0, 3, new Label(this, _("Move"))); - // TRANSLATORS: bot checker window table header - mPlayerTableTitleModel->set(0, 4, new Label(this, _("Result"))); - - mPlayerTitleTable->setLinewiseSelection(true); - - setWindowName("BotCheckerWindow"); - setCloseButton(true); - setStickyButtonLock(true); - setDefaultSize(w, h, ImageRect::CENTER); - - playersScrollArea->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); - - mPlayerTitleTable->setPosition(mPadding, mPadding); - mPlayerTitleTable->setWidth(w - 10); - mPlayerTitleTable->setHeight(20); - - playersScrollArea->setPosition(mPadding, 20 + 2 * mPadding); - playersScrollArea->setWidth(w - 15); - playersScrollArea->setHeight(h - 80); - - mIncButton->setPosition(mPadding, 190 + 3 * mPadding); - mIncButton->setWidth(80); - mIncButton->setHeight(20); - - add(mPlayerTitleTable); - add(playersScrollArea); - add(mIncButton); - - center(); - - setWidth(w); - setHeight(h); - loadWindowState(); - enableVisibleSound(true); - - config.addListener("enableBotCheker", this); - mEnabled = config.getBoolValue("enableBotCheker"); -} - -BotCheckerWindow::~BotCheckerWindow() -{ - config.removeListener("enableBotCheker", this); -} - -void BotCheckerWindow::slowLogic() -{ - BLOCK_START("BotCheckerWindow::slowLogic") - if (mEnabled && mTableModel) - { - const unsigned int nowTime = cur_time; - if (nowTime - mLastUpdateTime > 5 && mNeedUpdate) - { - mTableModel->playersUpdated(); - mNeedUpdate = false; - mLastUpdateTime = nowTime; - } - else if (nowTime - mLastUpdateTime > 15) - { - mTableModel->playersUpdated(); - mNeedUpdate = false; - mLastUpdateTime = nowTime; - } - } - BLOCK_END("BotCheckerWindow::slowLogic") -} - -void BotCheckerWindow::action(const gcn::ActionEvent &event) -{ - if (event.getId() == "reset") - { - reset(); - mNeedUpdate = true; - } -} - -void BotCheckerWindow::update() -{ -} - -void BotCheckerWindow::updateList() -{ - if (mTableModel) - mNeedUpdate = true; -} - -void BotCheckerWindow::reset() -{ - if (actorSpriteManager) - { - std::set beings = actorSpriteManager->getAll(); - FOR_EACH (ActorSprites::const_iterator, i, beings) - { - Being *const being = dynamic_cast(*i); - - if (being && being->getType() == Being::PLAYER - && being != player_node && being->getName() != "") - { - being->resetCounters(); - } - } - } -} - -void BotCheckerWindow::optionChanged(const std::string &name) -{ - if (name == "enableBotCheker") - mEnabled = config.getBoolValue("enableBotCheker"); -} - -#ifdef USE_PROFILER -void BotCheckerWindow::logicChildren() -{ - BLOCK_START("BotCheckerWindow::logicChildren") - BasicContainer::logicChildren(); - BLOCK_END("BotCheckerWindow::logicChildren") -} -#endif diff --git a/src/gui/botcheckerwindow.h b/src/gui/botcheckerwindow.h deleted file mode 100644 index fbe53cf82..000000000 --- a/src/gui/botcheckerwindow.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 Andrei Karas - * Copyright (C) 2011-2013 The ManaPlus developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_BOTCHECKERWINDOW_H -#define GUI_BOTCHECKERWINDOW_H - -#include "configlistener.h" - -#include "gui/widgets/window.h" - -#include - -struct BOTCHK final -{ - int16_t id; /**< Index into "botchecker_db" array */ - int16_t lv; - int16_t sp; -}; - -class Button; -class GuiTable; -class ScrollArea; -class UsersTableModel; -class StaticTableModel; - -class BotCheckerWindow final : public Window, - public gcn::ActionListener, - public ConfigListener -{ - public: - friend class UsersTableModel; - - /** - * Constructor. - */ - BotCheckerWindow(); - - A_DELETE_COPY(BotCheckerWindow) - - /** - * Destructor. - */ - ~BotCheckerWindow(); - - void action(const gcn::ActionEvent &event) override; - - void update(); - - void slowLogic(); - - void updateList(); - - void reset(); - - void optionChanged(const std::string &name) override; - -#ifdef USE_PROFILER - void logicChildren(); -#endif - - private: - UsersTableModel *mTableModel; - GuiTable *mTable; - ScrollArea *playersScrollArea; - StaticTableModel *mPlayerTableTitleModel; - GuiTable *mPlayerTitleTable; - Button *mIncButton; - int mLastUpdateTime; - bool mNeedUpdate; - bool mEnabled; -}; - -extern BotCheckerWindow *botCheckerWindow; - -#endif // GUI_BOTCHECKERWINDOW_H diff --git a/src/gui/buydialog.cpp b/src/gui/buydialog.cpp deleted file mode 100644 index 309a2922c..000000000 --- a/src/gui/buydialog.cpp +++ /dev/null @@ -1,553 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/buydialog.h" - -#include "shopitem.h" -#include "units.h" - -#include "gui/tradewindow.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/dropdown.h" -#include "gui/widgets/inttextfield.h" -#include "gui/widgets/label.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/scrollarea.h" -#include "gui/widgets/shopitems.h" -#include "gui/widgets/shoplistbox.h" -#include "gui/widgets/slider.h" - -#include "net/adminhandler.h" -#include "net/buysellhandler.h" -#include "net/net.h" -#include "net/npchandler.h" - -#include "resources/iteminfo.h" - -#include "utils/gettext.h" - -#include - -#include "debug.h" - -static const char *const SORT_NAME_BUY[7] = -{ - // TRANSLATORS: buy dialog sort type. - N_("unsorted"), - // TRANSLATORS: buy dialog sort type. - N_("by price"), - // TRANSLATORS: buy dialog sort type. - N_("by name"), - // TRANSLATORS: buy dialog sort type. - N_("by id"), - // TRANSLATORS: buy dialog sort type. - N_("by weight"), - // TRANSLATORS: buy dialog sort type. - N_("by amount"), - // TRANSLATORS: buy dialog sort type. - N_("by type") -}; - -class SortListModelBuy final : public gcn::ListModel -{ -public: - ~SortListModelBuy() - { } - - int getNumberOfElements() - { return 7; } - - std::string getElementAt(int i) - { - if (i >= getNumberOfElements() || i < 0) - return "???"; - return gettext(SORT_NAME_BUY[i]); - } -}; - -class SortItemPriceFunctor final -{ - public: - bool operator() (const ShopItem *const item1, - const ShopItem *const item2) const - { - if (!item1 || !item2) - return false; - - const int price1 = item1->getPrice(); - const int price2 = item2->getPrice(); - if (price1 == price2) - return item1->getDisplayName() < item2->getDisplayName(); - return price1 < price2; - } -} itemPriceBuySorter; - -class SortItemNameFunctor final -{ - public: - bool operator() (const ShopItem *const item1, - const ShopItem *const item2) const - { - if (!item1 || !item2) - return false; - - const std::string &name1 = item1->getDisplayName(); - const std::string &name2 = item2->getDisplayName(); - if (name1 == name2) - return item1->getPrice() < item2->getPrice(); - return name1 < name2; - } -} itemNameBuySorter; - -class SortItemIdFunctor final -{ - public: - bool operator() (const ShopItem *const item1, - const ShopItem *const item2) const - { - if (!item1 || !item2) - return false; - - const int id1 = item1->getId(); - const int id2 = item2->getId(); - if (id1 == id2) - return item1->getPrice() < item2->getPrice(); - return id1 < id2; - } -} itemIdBuySorter; - -class SortItemWeightFunctor final -{ - public: - bool operator() (const ShopItem *const item1, - const ShopItem *const item2) const - { - if (!item1 || !item2) - return false; - - const int weight1 = item1->getInfo().getWeight(); - const int weight2 = item2->getInfo().getWeight(); - if (weight1 == weight2) - return item1->getPrice() < item2->getPrice(); - return weight1 < weight2; - } -} itemWeightBuySorter; - -class SortItemAmountFunctor final -{ - public: - bool operator() (const ShopItem *const item1, - const ShopItem *const item2) const - { - if (!item1 || !item2) - return false; - - const int amount1 = item1->getQuantity(); - const int amount2 = item2->getQuantity(); - if (amount1 == amount2) - return item1->getPrice() < item2->getPrice(); - return amount1 < amount2; - } -} itemAmountBuySorter; - -class SortItemTypeFunctor final -{ - public: - bool operator() (const ShopItem *const item1, - const ShopItem *const item2) const - { - if (!item1 || !item2) - return false; - - const int type1 = item1->getInfo().getType(); - const int type2 = item2->getInfo().getType(); - if (type1 == type2) - return item1->getPrice() < item2->getPrice(); - return type1 < type2; - } -} itemTypeBuySorter; - -BuyDialog::DialogList BuyDialog::instances; - -BuyDialog::BuyDialog() : - // TRANSLATORS: buy dialog name - Window(_("Create items"), false, nullptr, "buy.xml"), - gcn::ActionListener(), - gcn::SelectionListener(), - mNpcId(-2), mMoney(0), mAmountItems(0), mMaxItems(0), mNick(), - mSortModel(nullptr), - mSortDropDown(nullptr) -{ - init(); -} - -BuyDialog::BuyDialog(const int npcId) : - // TRANSLATORS: buy dialog name - Window(_("Buy"), false, nullptr, "buy.xml"), - gcn::ActionListener(), - gcn::SelectionListener(), - mNpcId(npcId), mMoney(0), mAmountItems(0), mMaxItems(0), mNick(), - mSortModel(nullptr), - mSortDropDown(nullptr) -{ - init(); -} - -BuyDialog::BuyDialog(std::string nick) : - // TRANSLATORS: buy dialog name - Window(_("Buy"), false, nullptr, "buy.xml"), - gcn::ActionListener(), - gcn::SelectionListener(), - mNpcId(-1), mMoney(0), mAmountItems(0), mMaxItems(0), mNick(nick), - mSortModel(new SortListModelBuy), - mSortDropDown(new DropDown(this, mSortModel, false, false, this, "sort")) -{ - init(); -} - -void BuyDialog::init() -{ - setWindowName("Buy"); - setResizable(true); - setCloseButton(true); - setStickyButtonLock(true); - setMinWidth(260); - setMinHeight(220); - setDefaultSize(260, 230, ImageRect::CENTER); - - mShopItems = new ShopItems; - - mShopItemList = new ShopListBox(this, mShopItems, mShopItems); - mScrollArea = new ScrollArea(mShopItemList, - getOptionBool("showbackground"), "buy_background.xml"); - mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - - mSlider = new Slider(1.0); - mQuantityLabel = new Label(this, strprintf( - "%d / %d", mAmountItems, mMaxItems)); - mQuantityLabel->setAlignment(gcn::Graphics::CENTER); - // TRANSLATORS: buy dialog label - mMoneyLabel = new Label(this, strprintf( - _("Price: %s / Total: %s"), "", "")); - - mAmountField = new IntTextField(this, 1, 1, 123); - mAmountField->setActionEventId("amount"); - mAmountField->addActionListener(this); - mAmountField->setSendAlwaysEvents(true); - mAmountField->setEnabled(false); - - // TRANSLATORS: buy dialog label - mAmountLabel = new Label(this, _("Amount:")); - mAmountLabel->adjustSize(); - - // TRANSLATORS: This is a narrow symbol used to denote 'increasing'. - // You may change this symbol if your language uses another. - mIncreaseButton = new Button(this, _("+"), "inc", this); - // TRANSLATORS: This is a narrow symbol used to denote 'decreasing'. - // You may change this symbol if your language uses another. - mDecreaseButton = new Button(this, _("-"), "dec", this); - // TRANSLATORS: buy dialog button - mBuyButton = new Button(this, mNpcId == -2 - ? _("Create") :_("Buy"), "buy", this); - // TRANSLATORS: buy dialog button - mQuitButton = new Button(this, _("Quit"), "quit", this); - // TRANSLATORS: buy dialog button - mAddMaxButton = new Button(this, _("Max"), "max", this); - - mDecreaseButton->adjustSize(); - mDecreaseButton->setWidth(mIncreaseButton->getWidth()); - - mIncreaseButton->setEnabled(false); - mDecreaseButton->setEnabled(false); - mBuyButton->setEnabled(false); - mSlider->setEnabled(false); - - mSlider->setActionEventId("slider"); - mSlider->addActionListener(this); - - mShopItemList->setDistributeMousePressed(false); - mShopItemList->setActionEventId("buy"); - mShopItemList->addActionListener(this); - mShopItemList->addSelectionListener(this); - - ContainerPlacer placer = getPlacer(0, 0); - placer(0, 0, mScrollArea, 9, 5).setPadding(3); - placer(0, 5, mDecreaseButton); - placer(1, 5, mSlider, 4); - placer(5, 5, mIncreaseButton); - placer(6, 5, mQuantityLabel, 2); - placer(8, 5, mAddMaxButton); - placer(0, 6, mAmountLabel, 2); - placer(2, 6, mAmountField, 2); - placer(0, 7, mMoneyLabel, 8); - if (mSortDropDown) - placer(0, 8, mSortDropDown, 2); - placer(7, 8, mBuyButton); - placer(8, 8, mQuitButton); - - Layout &layout = getLayout(); - layout.setRowHeight(0, Layout::AUTO_SET); - - center(); - loadWindowState(); - enableVisibleSound(true); - - instances.push_back(this); - setVisible(true); -} - -BuyDialog::~BuyDialog() -{ - delete mShopItems; - mShopItems = nullptr; - - instances.remove(this); -} - -void BuyDialog::setMoney(const int amount) -{ - mMoney = amount; - mShopItemList->setPlayersMoney(amount); - - updateButtonsAndLabels(); -} - -void BuyDialog::reset() -{ - mShopItems->clear(); - mShopItemList->adjustSize(); - - // Reset previous selected items to prevent failing asserts - mShopItemList->setSelected(-1); - mSlider->setValue(0); - - setMoney(0); -} - -void BuyDialog::addItem(const int id, const unsigned char color, - const int amount, const int price) -{ - mShopItems->addItem(id, color, amount, price); - mShopItemList->adjustSize(); -} - -void BuyDialog::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "quit") - { - close(); - return; - } - else if (eventId == "sort") - { - if (mSortDropDown && mShopItems) - { - std::vector &items = mShopItems->items(); - switch (mSortDropDown->getSelected()) - { - case 1: - std::sort(items.begin(), items.end(), itemPriceBuySorter); - break; - case 2: - std::sort(items.begin(), items.end(), itemNameBuySorter); - break; - case 3: - std::sort(items.begin(), items.end(), itemIdBuySorter); - break; - case 4: - std::sort(items.begin(), items.end(), itemWeightBuySorter); - break; - case 5: - std::sort(items.begin(), items.end(), itemAmountBuySorter); - break; - case 6: - std::sort(items.begin(), items.end(), itemTypeBuySorter); - break; - case 0: - default: - break; - } - } - return; - } - - const int selectedItem = mShopItemList->getSelected(); - - // The following actions require a valid selection - if (selectedItem < 0 || selectedItem >= mShopItems->getNumberOfElements()) - return; - - if (eventId == "slider") - { - mAmountItems = static_cast(mSlider->getValue()); - mAmountField->setValue(mAmountItems); - updateButtonsAndLabels(); - } - else if (eventId == "inc" && mAmountItems < mMaxItems) - { - mAmountItems++; - mSlider->setValue(mAmountItems); - mAmountField->setValue(mAmountItems); - updateButtonsAndLabels(); - } - else if (eventId == "dec" && mAmountItems > 1) - { - mAmountItems--; - mSlider->setValue(mAmountItems); - mAmountField->setValue(mAmountItems); - updateButtonsAndLabels(); - } - else if (eventId == "max") - { - mAmountItems = mMaxItems; - mSlider->setValue(mAmountItems); - mAmountField->setValue(mAmountItems); - updateButtonsAndLabels(); - } - else if (eventId == "amount") - { - mAmountItems = mAmountField->getValue(); - mSlider->setValue(mAmountItems); - updateButtonsAndLabels(); - } - else if (eventId == "buy" && mAmountItems > 0 && mAmountItems <= mMaxItems) - { - if (mNpcId == -2) - { - const ShopItem *const item = mShopItems->at(selectedItem); - Net::getAdminHandler()->createItems(item->getId(), - mAmountItems, item->getColor()); - } - else if (mNpcId != -1) - { - const ShopItem *const item = mShopItems->at(selectedItem); - Net::getNpcHandler()->buyItem(mNpcId, item->getId(), - item->getColor(), mAmountItems); - - // Update money and adjust the max number of items - // that can be bought - mMaxItems -= mAmountItems; - setMoney(mMoney - - mAmountItems * mShopItems->at(selectedItem)->getPrice()); - - // Reset selection - mAmountItems = 1; - mSlider->setValue(1); - mSlider->setScale(1, mMaxItems); - } - else if (tradeWindow) - { - const ShopItem *const item = mShopItems->at(selectedItem); - if (item) - { - Net::getBuySellHandler()->sendBuyRequest(mNick, - item, mAmountItems); - if (tradeWindow) - { - tradeWindow->addAutoMoney(mNick, - item->getPrice() * mAmountItems); - } - } - } - } -} - -void BuyDialog::valueChanged(const gcn::SelectionEvent &event A_UNUSED) -{ - // Reset amount of items and update labels - mAmountItems = 1; - mSlider->setValue(1); - - updateButtonsAndLabels(); - mSlider->setScale(1, mMaxItems); - mAmountField->setRange(1, mMaxItems); - mAmountField->setValue(1); -} - -void BuyDialog::updateButtonsAndLabels() -{ - const int selectedItem = mShopItemList->getSelected(); - int price = 0; - - if (selectedItem > -1) - { - const ShopItem *const item = mShopItems->at(selectedItem); - if (item) - { - const int itemPrice = item->getPrice(); - - // Calculate how many the player can afford - if (mNpcId == -2) - mMaxItems = 100; - else if (itemPrice) - mMaxItems = mMoney / itemPrice; - else - mMaxItems = 1; - - if (item->getQuantity() > 0 && mMaxItems > item->getQuantity()) - mMaxItems = item->getQuantity(); - - if (mAmountItems > mMaxItems) - mAmountItems = mMaxItems; - - price = mAmountItems * itemPrice; - } - } - else - { - mMaxItems = 0; - mAmountItems = 0; - } - - mIncreaseButton->setEnabled(mAmountItems < mMaxItems); - mDecreaseButton->setEnabled(mAmountItems > 1); - mBuyButton->setEnabled(mAmountItems > 0); - mSlider->setEnabled(mMaxItems > 1); - mAmountField->setEnabled(mAmountItems > 0); - - mQuantityLabel->setCaption(strprintf("%d / %d", mAmountItems, mMaxItems)); - // TRANSLATORS: buy dialog label - mMoneyLabel->setCaption(strprintf(_("Price: %s / Total: %s"), - Units::formatCurrency(price).c_str(), - Units::formatCurrency(mMoney - price).c_str())); -} - -void BuyDialog::setVisible(bool visible) -{ - Window::setVisible(visible); - - if (visible && mShopItemList) - mShopItemList->requestFocus(); - else - scheduleDelete(); -} - -void BuyDialog::closeAll() -{ - FOR_EACH (DialogList::const_iterator, it, instances) - { - if (*it) - (*it)->close(); - } -} diff --git a/src/gui/buydialog.h b/src/gui/buydialog.h deleted file mode 100644 index 875184851..000000000 --- a/src/gui/buydialog.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_BUYDIALOG_H -#define GUI_BUYDIALOG_H - -#include "gui/widgets/window.h" - -#include -#include - -class Button; -class DropDown; -class ShopItems; -class ShopListBox; -class SortListModelBuy; -class IntTextField; -class Label; -class ListBox; -class ScrollArea; -class Slider; - -/** - * The buy dialog. - * - * \ingroup Interface - */ -class BuyDialog final : public Window, - public gcn::ActionListener, - public gcn::SelectionListener -{ - public: - /** - * Constructor. - * - * @see Window::Window - */ - BuyDialog(); - - /** - * Constructor. - * - * @see Window::Window - */ - explicit BuyDialog(const int npcId); - - /** - * Constructor. - * - * @see Window::Window - */ - explicit BuyDialog(std::string nick); - - A_DELETE_COPY(BuyDialog) - - /** - * Destructor - */ - ~BuyDialog(); - - void init(); - - /** - * Resets the dialog, clearing shop inventory. - */ - void reset(); - - /** - * Sets the amount of available money. - */ - void setMoney(const int amount); - - /** - * Adds an item to the shop inventory. - */ - void addItem(const int id, const unsigned char color, - const int amount, const int price); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - /** - * Returns the number of items in the shop inventory. - */ - int getNumberOfElements() A_WARN_UNUSED; - - /** - * Updates the labels according to the selected item. - */ - void valueChanged(const gcn::SelectionEvent &event) override; - - /** - * Updates the state of buttons and labels. - */ - void updateButtonsAndLabels(); - - /** - * Sets the visibility of this window. - */ - void setVisible(bool visible); - - /** - * Returns true if any instances exist. - */ - static bool isActive() A_WARN_UNUSED - { return !instances.empty(); } - - /** - * Closes all instances. - */ - static void closeAll(); - - private: - typedef std::list DialogList; - static DialogList instances; - - int mNpcId; - - Button *mBuyButton; - Button *mQuitButton; - Button *mAddMaxButton; - Button *mIncreaseButton; - Button *mDecreaseButton; - ShopListBox *mShopItemList; - ScrollArea *mScrollArea; - Label *mMoneyLabel; - Label *mQuantityLabel; - Slider *mSlider; - Label *mAmountLabel; - IntTextField *mAmountField; - - ShopItems *mShopItems; - - int mMoney; - int mAmountItems; - int mMaxItems; - std::string mNick; - SortListModelBuy *mSortModel; - DropDown *mSortDropDown; -}; - -#endif // GUI_BUYDIALOG_H diff --git a/src/gui/buyselldialog.cpp b/src/gui/buyselldialog.cpp deleted file mode 100644 index 13de9c440..000000000 --- a/src/gui/buyselldialog.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/buyselldialog.h" - -#include "net/buysellhandler.h" -#include "net/net.h" -#include "net/npchandler.h" - -#include "gui/widgets/button.h" - -#include "utils/gettext.h" - -#include "debug.h" - -BuySellDialog::DialogList BuySellDialog::dialogInstances; - -BuySellDialog::BuySellDialog(const int npcId) : - // TRANSLATORS: shop window name - Window(_("Shop"), false, nullptr, "buysell.xml"), - gcn::ActionListener(), - mNpcId(npcId), - mNick(""), - mBuyButton(nullptr) -{ - init(); -} - -BuySellDialog::BuySellDialog(const std::string &nick) : - // TRANSLATORS: shop window name - Window(_("Shop"), false, nullptr, "buysell.xml"), - gcn::ActionListener(), - mNpcId(-1), - mNick(nick), - mBuyButton(nullptr) -{ - init(); -} - -void BuySellDialog::init() -{ - setWindowName("BuySell"); - setCloseButton(true); - - static const char *buttonNames[] = - { - // TRANSLATORS: shop window button - N_("Buy"), - // TRANSLATORS: shop window button - N_("Sell"), - // TRANSLATORS: shop window button - N_("Cancel"), - nullptr - }; - const int buttonPadding = getOption("buttonpadding", 10); - int x = buttonPadding; - const int y = buttonPadding; - - for (const char *const *curBtn = buttonNames; *curBtn; curBtn++) - { - Button *const btn = new Button(this, gettext(*curBtn), *curBtn, this); - if (!mBuyButton) - mBuyButton = btn; // For focus request - btn->setPosition(x, y); - add(btn); - x += btn->getWidth() + buttonPadding; - } - if (mBuyButton) - { - mBuyButton->requestFocus(); - setContentSize(x, 2 * y + mBuyButton->getHeight()); - } - - center(); - setDefaultSize(); - loadWindowState(); - enableVisibleSound(true); - - dialogInstances.push_back(this); - setVisible(true); -} - -BuySellDialog::~BuySellDialog() -{ - dialogInstances.remove(this); -} - -void BuySellDialog::setVisible(bool visible) -{ - Window::setVisible(visible); - - if (visible) - { - if (mBuyButton) - mBuyButton->requestFocus(); - } - else - { - scheduleDelete(); - } -} - -void BuySellDialog::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "Buy") - { - if (mNpcId != -1) - Net::getNpcHandler()->buy(mNpcId); - else - Net::getBuySellHandler()->requestSellList(mNick); - } - else if (eventId == "Sell") - { - if (mNpcId != -1) - Net::getNpcHandler()->sell(mNpcId); - else - Net::getBuySellHandler()->requestBuyList(mNick); - } - - close(); -} - -void BuySellDialog::closeAll() -{ - FOR_EACH (DialogList::const_iterator, it, dialogInstances) - { - if (*it) - (*it)->close(); - } -} diff --git a/src/gui/buyselldialog.h b/src/gui/buyselldialog.h deleted file mode 100644 index 193364ff8..000000000 --- a/src/gui/buyselldialog.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_BUYSELLDIALOG_H -#define GUI_BUYSELLDIALOG_H - -#include "gui/widgets/window.h" - -#include - -class Button; - -/** - * A dialog to choose between buying or selling at a shop. - * - * \ingroup Interface - */ -class BuySellDialog final : public Window, public gcn::ActionListener -{ - public: - /** - * Constructor. The action listener passed will receive "sell", "buy" - * or "cancel" events when the respective buttons are pressed. - * - * @see Window::Window - */ - explicit BuySellDialog(const int npcId); - - explicit BuySellDialog(const std::string &nick); - - A_DELETE_COPY(BuySellDialog) - - ~BuySellDialog(); - - void init(); - - void setVisible(bool visible); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - /** - * Returns true if any instances exist. - */ - static bool isActive() A_WARN_UNUSED - { return !dialogInstances.empty(); } - - /** - * Closes all instances. - */ - static void closeAll(); - - private: - typedef std::list DialogList; - static DialogList dialogInstances; - - int mNpcId; - std::string mNick; - Button *mBuyButton; -}; - -#endif // GUI_BUYSELLDIALOG_H diff --git a/src/gui/changeemaildialog.cpp b/src/gui/changeemaildialog.cpp deleted file mode 100644 index cd10b8dfa..000000000 --- a/src/gui/changeemaildialog.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2008-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/changeemaildialog.h" - -#include "client.h" - -#include "gui/registerdialog.h" -#include "gui/okdialog.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/label.h" -#include "gui/widgets/textfield.h" - -#include "net/logindata.h" -#include "net/loginhandler.h" -#include "net/net.h" - -#include "utils/gettext.h" - -#include -#include - -#include "debug.h" - -ChangeEmailDialog::ChangeEmailDialog(LoginData *const data): - // TRANSLATORS: change email dialog header - Window(_("Change Email Address"), true, nullptr, "changeemail.xml"), - gcn::ActionListener(), - mFirstEmailField(new TextField(this)), - mSecondEmailField(new TextField(this)), - // TRANSLATORS: button in change email dialog - mChangeEmailButton(new Button(this, _("Change Email Address"), - "change_email", this)), - // TRANSLATORS: button in change email dialog - mCancelButton(new Button(this, _("Cancel"), "cancel", this)), - mWrongDataNoticeListener(new WrongDataNoticeListener), - mLoginData(data) -{ - // TRANSLATORS: label in change email dialog - Label *const accountLabel = new Label(this, strprintf(_("Account: %s"), - mLoginData->username.c_str())); - Label *const newEmailLabel = new Label(this, - // TRANSLATORS: label in change email dialog - _("Type new email address twice:")); - - const int width = 200; - const int height = 130; - setContentSize(width, height); - - accountLabel->setPosition(5, 5); - accountLabel->setWidth(130); - - newEmailLabel->setPosition( - 5, accountLabel->getY() + accountLabel->getHeight() + 7); - newEmailLabel->setWidth(width - 5); - - mFirstEmailField->setPosition( - 5, newEmailLabel->getY() + newEmailLabel->getHeight() + 7); - mFirstEmailField->setWidth(130); - - mSecondEmailField->setPosition( - 5, mFirstEmailField->getY() + mFirstEmailField->getHeight() + 7); - mSecondEmailField->setWidth(130); - - mCancelButton->setPosition( - width - 5 - mCancelButton->getWidth(), - height - 5 - mCancelButton->getHeight()); - mChangeEmailButton->setPosition( - mCancelButton->getX() - 5 - mChangeEmailButton->getWidth(), - mCancelButton->getY()); - - add(accountLabel); - add(newEmailLabel); - add(mFirstEmailField); - add(mSecondEmailField); - add(mChangeEmailButton); - add(mCancelButton); - - center(); - setVisible(true); - mFirstEmailField->requestFocus(); - - mFirstEmailField->setActionEventId("change_email"); - mSecondEmailField->setActionEventId("change_email"); -} - -ChangeEmailDialog::~ChangeEmailDialog() -{ - delete mWrongDataNoticeListener; - mWrongDataNoticeListener = nullptr; -} - -void ChangeEmailDialog::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "cancel") - { - client->setState(STATE_CHAR_SELECT); - } - else if (eventId == "change_email") - { - const std::string username = mLoginData->username.c_str(); - const std::string newFirstEmail = mFirstEmailField->getText(); - const std::string newSecondEmail = mSecondEmailField->getText(); - logger->log("ChangeEmailDialog::Email change, Username is %s", - username.c_str()); - - std::stringstream errorMsg; - int error = 0; - - const unsigned int min = Net::getLoginHandler() - ->getMinPasswordLength(); - const unsigned int max = Net::getLoginHandler() - ->getMaxPasswordLength(); - - if (newFirstEmail.length() < min) - { - // First email address too short - // TRANSLATORS: change email error - errorMsg << strprintf(_("The new email address needs to be at " - "least %u characters long."), min); - error = 1; - } - else if (newFirstEmail.length() > max) - { - // First email address too long - // TRANSLATORS: change email error - errorMsg << strprintf(_("The new email address needs to be " - "less than %u characters long."), max); - error = 1; - } - else if (newFirstEmail != newSecondEmail) - { - // Second Pass mismatch - // TRANSLATORS: change email error - errorMsg << _("The email address entries mismatch."); - error = 2; - } - - if (error > 0) - { - if (error == 1) - mWrongDataNoticeListener->setTarget(this->mFirstEmailField); - else if (error == 2) - mWrongDataNoticeListener->setTarget(this->mSecondEmailField); - - // TRANSLATORS: change email error header - OkDialog *const dlg = new OkDialog(_("Error"), - errorMsg.str(), DIALOG_ERROR); - dlg->addActionListener(mWrongDataNoticeListener); - } - else - { - // No errors detected, change account password. - mChangeEmailButton->setEnabled(false); - // Set the new email address - mLoginData->email = newFirstEmail; - client->setState(STATE_CHANGEEMAIL_ATTEMPT); - } - } -} diff --git a/src/gui/changeemaildialog.h b/src/gui/changeemaildialog.h deleted file mode 100644 index e61ac8bc5..000000000 --- a/src/gui/changeemaildialog.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2008-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_CHANGEEMAILDIALOG_H -#define GUI_CHANGEEMAILDIALOG_H - -#include "gui/widgets/window.h" - -#include - -class Button; -class LoginData; -class TextField; -class WrongDataNoticeListener; - -/** - * The Change email dialog. - * - * \ingroup Interface - */ -class ChangeEmailDialog final : public Window, public gcn::ActionListener -{ - public: - /** - * Constructor. - * - * @see Window::Window - */ - explicit ChangeEmailDialog(LoginData *const data); - - A_DELETE_COPY(ChangeEmailDialog) - - /** - * Destructor. - */ - ~ChangeEmailDialog(); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - /** - * This is used to pass the pointer to where the new email should be - * put when the dialog finishes. - */ - static void setEmail(std::string *email); - - private: - TextField *mFirstEmailField; - TextField *mSecondEmailField; - - Button *mChangeEmailButton; - Button *mCancelButton; - - WrongDataNoticeListener *mWrongDataNoticeListener; - - LoginData *mLoginData; -}; - -#endif // GUI_CHANGEEMAILDIALOG_H diff --git a/src/gui/changepassworddialog.cpp b/src/gui/changepassworddialog.cpp deleted file mode 100644 index 3f41df3c5..000000000 --- a/src/gui/changepassworddialog.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/changepassworddialog.h" - -#include "client.h" - -#include "gui/registerdialog.h" -#include "gui/okdialog.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/passwordfield.h" -#include "gui/widgets/label.h" -#include "gui/widgets/layout.h" - -#include "net/logindata.h" -#include "net/loginhandler.h" -#include "net/net.h" - -#include "utils/gettext.h" - -#include -#include - -#include "debug.h" - -ChangePasswordDialog::ChangePasswordDialog(LoginData *const data): - // TRANSLATORS: change password window name - Window(_("Change Password"), true, nullptr, "changepassword.xml"), - gcn::ActionListener(), - mOldPassField(new PasswordField(this)), - mFirstPassField(new PasswordField(this)), - mSecondPassField(new PasswordField(this)), - // TRANSLATORS: change password dialog button - mChangePassButton(new Button(this, _("Change Password"), - "change_password", this)), - // TRANSLATORS: change password dialog button - mCancelButton(new Button(this, _("Cancel"), "cancel", this)), - mWrongDataNoticeListener(new WrongDataNoticeListener), - mLoginData(data) -{ - Label *const accountLabel = new Label(this, - // TRANSLATORS: change password dialog label - strprintf(_("Account: %s"), mLoginData->username.c_str())); - - place(0, 0, accountLabel, 3); - // TRANSLATORS: change password dialog label - place(0, 1, new Label(this, _("Password:")), 3); - place(0, 2, mOldPassField, 3).setPadding(1); - // TRANSLATORS: change password dialog label - place(0, 3, new Label(this, _("Type new password twice:")), 3); - place(0, 4, mFirstPassField, 3).setPadding(1); - place(0, 5, mSecondPassField, 3).setPadding(1); - place(1, 6, mCancelButton); - place(2, 6, mChangePassButton); - reflowLayout(200); - - center(); - setVisible(true); - mOldPassField->requestFocus(); - - mOldPassField->setActionEventId("change_password"); - mFirstPassField->setActionEventId("change_password"); - mSecondPassField->setActionEventId("change_password"); -} - -ChangePasswordDialog::~ChangePasswordDialog() -{ - delete mWrongDataNoticeListener; - mWrongDataNoticeListener = nullptr; -} - -void ChangePasswordDialog::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "cancel") - { - client->setState(STATE_CHAR_SELECT); - } - else if (eventId == "change_password") - { - const std::string username = mLoginData->username.c_str(); - const std::string oldPassword = mOldPassField->getText(); - const std::string newFirstPass = mFirstPassField->getText(); - const std::string newSecondPass = mSecondPassField->getText(); - logger->log("ChangePasswordDialog::Password change, Username is %s", - username.c_str()); - - std::stringstream errorMsg; - int error = 0; - - const unsigned int min = Net::getLoginHandler() - ->getMinPasswordLength(); - const unsigned int max = Net::getLoginHandler() - ->getMaxPasswordLength(); - - // Check old Password - if (oldPassword.empty()) - { - // No old password - // TRANSLATORS: change password error - errorMsg << _("Enter the old password first."); - error = 1; - } - else if (newFirstPass.length() < min) - { - // First password too short - // TRANSLATORS: change password error - errorMsg << strprintf(_("The new password needs to be at least" - " %u characters long."), min); - error = 2; - } - else if (newFirstPass.length() > max) - { - // First password too long - // TRANSLATORS: change password error - errorMsg << strprintf(_("The new password needs to be less " - "than %u characters long."), max); - error = 2; - } - else if (newFirstPass != newSecondPass) - { - // Second Pass mismatch - // TRANSLATORS: change password error - errorMsg << _("The new password entries mismatch."); - error = 3; - } - - if (error > 0) - { - if (error == 1) - mWrongDataNoticeListener->setTarget(this->mOldPassField); - else if (error == 2) - mWrongDataNoticeListener->setTarget(this->mFirstPassField); - else if (error == 3) - mWrongDataNoticeListener->setTarget(this->mSecondPassField); - - // TRANSLATORS: change password error header - OkDialog *const dlg = new OkDialog(_("Error"), - errorMsg.str(), DIALOG_ERROR); - dlg->addActionListener(mWrongDataNoticeListener); - } - else - { - // No errors detected, change account password. - mChangePassButton->setEnabled(false); - // Set the new password - mLoginData->password = oldPassword; - mLoginData->newPassword = newFirstPass; - client->setState(STATE_CHANGEPASSWORD_ATTEMPT); - } - } -} diff --git a/src/gui/changepassworddialog.h b/src/gui/changepassworddialog.h deleted file mode 100644 index fd70348a6..000000000 --- a/src/gui/changepassworddialog.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_CHANGEPASSWORDDIALOG_H -#define GUI_CHANGEPASSWORDDIALOG_H - -#include "gui/widgets/window.h" - -#include - -class Button; -class LoginData; -class TextField; -class WrongDataNoticeListener; - -/** - * The Change password dialog. - * - * \ingroup Interface - */ -class ChangePasswordDialog final : public Window, public gcn::ActionListener -{ - public: - /** - * Constructor - * - * @see Window::Window - */ - explicit ChangePasswordDialog(LoginData *const data); - - A_DELETE_COPY(ChangePasswordDialog) - - /** - * Destructor - */ - ~ChangePasswordDialog(); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - private: - TextField *mOldPassField; - TextField *mFirstPassField; - TextField *mSecondPassField; - - Button *mChangePassButton; - Button *mCancelButton; - - WrongDataNoticeListener *mWrongDataNoticeListener; - - LoginData *mLoginData; -}; - -#endif // GUI_CHANGEPASSWORDDIALOG_H diff --git a/src/gui/charcreatedialog.cpp b/src/gui/charcreatedialog.cpp deleted file mode 100644 index fbcabe3c3..000000000 --- a/src/gui/charcreatedialog.cpp +++ /dev/null @@ -1,698 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/charcreatedialog.h" - -#include "main.h" - -#include "input/keydata.h" -#include "input/keyevent.h" - -#include "gui/okdialog.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/label.h" -#include "gui/widgets/playerbox.h" -#include "gui/widgets/radiobutton.h" -#include "gui/widgets/slider.h" -#include "gui/widgets/textfield.h" - -#include "net/net.h" - -#include "resources/chardb.h" -#include "resources/colordb.h" -#include "resources/itemdb.h" -#include "resources/iteminfo.h" - -#include "utils/gettext.h" - -#include "debug.h" - -extern int serverVersion; - -static const Being::Action actions[] = -{ - Being::STAND, Being::SIT, Being::MOVE, Being::ATTACK, Being::DEAD -}; - -static const uint8_t directions[] = -{ - Being::DOWN, Being::RIGHT, Being::UP, Being::LEFT -}; - -CharCreateDialog::CharCreateDialog(CharSelectDialog *const parent, - const int slot) : - // TRANSLATORS: char create dialog name - Window(_("New Character"), true, parent, "charcreate.xml"), - gcn::ActionListener(), - gcn::KeyListener(), - mCharSelectDialog(parent), - mNameField(new TextField(this, "")), - // TRANSLATORS: char create dialog label - mNameLabel(new Label(this, _("Name:"))), - // TRANSLATORS: This is a narrow symbol used to denote 'next'. - // You may change this symbol if your language uses another. - // TRANSLATORS: char create dialog button - mNextHairColorButton(new Button(this, _(">"), "nextcolor", this)), - // TRANSLATORS: This is a narrow symbol used to denote 'previous'. - // You may change this symbol if your language uses another. - // TRANSLATORS: char create dialog button - mPrevHairColorButton(new Button(this, _("<"), "prevcolor", this)), - // TRANSLATORS: char create dialog label - mHairColorLabel(new Label(this, _("Hair color:"))), - mHairColorNameLabel(new Label(this, "")), - // TRANSLATORS: char create dialog button - mNextHairStyleButton(new Button(this, _(">"), "nextstyle", this)), - // TRANSLATORS: char create dialog button - mPrevHairStyleButton(new Button(this, _("<"), "prevstyle", this)), - // TRANSLATORS: char create dialog label - mHairStyleLabel(new Label(this, _("Hair style:"))), - mHairStyleNameLabel(new Label(this, "")), - mNextRaceButton(nullptr), - mPrevRaceButton(nullptr), - mRaceLabel(nullptr), - mRaceNameLabel(nullptr), - mNextLookButton(nullptr), - mPrevLookButton(nullptr), - mLookLabel(nullptr), - mLookNameLabel(nullptr), - // TRANSLATORS: char create dialog button - mActionButton(new Button(this, _("^"), "action", this)), - // TRANSLATORS: char create dialog button - mRotateButton(new Button(this, _(">"), "rotate", this)), - // TRANSLATORS: char create dialog button - mMale(new RadioButton(this, _("Male"), "gender")), - // TRANSLATORS: char create dialog button - mFemale(new RadioButton(this, _("Female"), "gender")), - // TRANSLATORS: char create dialog button - mOther(new RadioButton(this, _("Other"), "gender")), - mAttributeSlider(), - mAttributeLabel(), - mAttributeValue(), - mAttributesLeft(new Label(this, - // TRANSLATORS: char create dialog label - strprintf(_("Please distribute %d points"), 99))), - mMaxPoints(0), - mUsedPoints(0), - // TRANSLATORS: char create dialog button - mCreateButton(new Button(this, _("Create"), "create", this)), - // TRANSLATORS: char create dialog button - mCancelButton(new Button(this, _("Cancel"), "cancel", this)), - mRace(0), - mLook(0), - mMinLook(CharDB::getMinLook()), - mMaxLook(CharDB::getMaxLook()), - mPlayer(new Being(0, ActorSprite::PLAYER, static_cast(mRace), - nullptr)), - mPlayerBox(new PlayerBox(mPlayer, "charcreate_playerbox.xml", - "charcreate_selectedplayerbox.xml")), - mHairStyle(0), - mHairColor(0), - mSlot(slot), - maxHairColor(CharDB::getMaxHairColor()), - minHairColor(CharDB::getMinHairColor()), - maxHairStyle(CharDB::getMaxHairStyle()), - minHairStyle(CharDB::getMinHairStyle()), - mAction(0), - mDirection(0) -{ - setStickyButtonLock(true); - setSticky(true); - setWindowName("NewCharacter"); - - mPlayer->setGender(GENDER_MALE); - const std::vector &items = CharDB::getDefaultItems(); - int i = 1; - for (std::vector::const_iterator it = items.begin(), - it_end = items.end(); - it != it_end; ++ it, i ++) - { - mPlayer->setSprite(i, *it); - } - - if (!maxHairColor) - maxHairColor = ColorDB::getHairSize(); - if (!maxHairStyle) - maxHairStyle = mPlayer->getNumOfHairstyles(); - - if (maxHairStyle) - mHairStyle = (rand() % maxHairStyle) + minHairStyle; - else - mHairStyle = 0; - if (maxHairColor) - mHairColor = (rand() % maxHairColor) + minHairColor; - else - mHairColor = 0; - - mNameField->setMaximum(24); - - if (serverVersion >= 2) - { - // TRANSLATORS: char create dialog button - mNextRaceButton = new Button(this, _(">"), "nextrace", this); - // TRANSLATORS: char create dialog button - mPrevRaceButton = new Button(this, _("<"), "prevrace", this); - // TRANSLATORS: char create dialog label - mRaceLabel = new Label(this, _("Race:")); - mRaceNameLabel = new Label(this, ""); - } - if (serverVersion >= 9 && mMinLook < mMaxLook) - { - // TRANSLATORS: char create dialog button - mNextLookButton = new Button(this, _(">"), "nextlook", this); - // TRANSLATORS: char create dialog button - mPrevLookButton = new Button(this, _("<"), "prevlook", this); - // TRANSLATORS: char create dialog label - mLookLabel = new Label(this, _("Look:")); - mLookNameLabel = new Label(this, ""); - } - - // Default to a Male character - mMale->setSelected(true); - - mMale->setActionEventId("gender"); - mFemale->setActionEventId("gender"); - mOther->setActionEventId("gender"); - - mMale->addActionListener(this); - mFemale->addActionListener(this); - mOther->addActionListener(this); - - mPlayerBox->setWidth(74); - - mNameField->setActionEventId("create"); - mNameField->addActionListener(this); - - const int w = 480; - const int h = 350; - - setContentSize(w, h); - mPlayerBox->setDimension(gcn::Rectangle(360, 0, 110, 90)); - mActionButton->setPosition(385, 100); - mRotateButton->setPosition(415, 100); - - mNameLabel->setPosition(5, 2); - mNameField->setDimension( - gcn::Rectangle(60, 2, 300, mNameField->getHeight())); - - const int leftX = 120; - const int rightX = 300; - const int labelX = 5; - const int nameX = 145; - int y = 30; - mPrevHairColorButton->setPosition(leftX, y); - mNextHairColorButton->setPosition(rightX, y); - y += 5; - mHairColorLabel->setPosition(labelX, y); - mHairColorNameLabel->setPosition(nameX, y); - y += 24; - mPrevHairStyleButton->setPosition(leftX, y); - mNextHairStyleButton->setPosition(rightX, y); - y += 5; - mHairStyleLabel->setPosition(labelX, y); - mHairStyleNameLabel->setPosition(nameX, y); - - if (serverVersion >= 9 && mMinLook < mMaxLook) - { - y += 24; - mPrevLookButton->setPosition(leftX, y); - mNextLookButton->setPosition(rightX, y); - y += 5; - mLookLabel->setPosition(labelX, y); - mLookNameLabel->setPosition(nameX, y); // 93 - } - if (serverVersion >= 2) - { - y += 24; - mPrevRaceButton->setPosition(leftX, y); - mNextRaceButton->setPosition(rightX, y); - y += 5; - mRaceLabel->setPosition(labelX, y); - mRaceNameLabel->setPosition(nameX, y); - } - - updateSliders(); - setButtonsPosition(w, h); - - mMale->setPosition(30, 120); - mFemale->setPosition(100, 120); - mOther->setPosition(170, 120); - - add(mPlayerBox); - add(mNameField); - add(mNameLabel); - add(mNextHairColorButton); - add(mPrevHairColorButton); - add(mHairColorLabel); - add(mHairColorNameLabel); - add(mNextHairStyleButton); - add(mPrevHairStyleButton); - add(mHairStyleLabel); - add(mHairStyleNameLabel); - add(mActionButton); - add(mRotateButton); - - if (serverVersion >= 9 && mMinLook < mMaxLook) - { - add(mNextLookButton); - add(mPrevLookButton); - add(mLookLabel); - add(mLookNameLabel); - } - - if (serverVersion >= 2) - { - add(mNextRaceButton); - add(mPrevRaceButton); - add(mRaceLabel); - add(mRaceNameLabel); - } - - add(mAttributesLeft); - add(mCreateButton); - add(mCancelButton); - - add(mMale); - add(mFemale); - add(mOther); - - center(); - setVisible(true); - mNameField->requestFocus(); - - updateHair(); - if (serverVersion >= 2) - updateRace(); - if (serverVersion >= 9 && mMinLook < mMaxLook) - updateLook(); - updatePlayer(); - - addKeyListener(this); -} - -CharCreateDialog::~CharCreateDialog() -{ - delete mPlayer; - mPlayer = nullptr; - - if (Net::getCharServerHandler()) - Net::getCharServerHandler()->setCharCreateDialog(nullptr); -} - -void CharCreateDialog::action(const gcn::ActionEvent &event) -{ - const std::string id = event.getId(); - if (id == "create") - { - if ( -#ifdef MANASERV_SUPPORT - Net::getNetworkType() == ServerInfo::MANASERV || -#endif - getName().length() >= 4) - { - // Attempt to create the character - mCreateButton->setEnabled(false); - - std::vector atts; - for (size_t i = 0, sz = mAttributeSlider.size(); i < sz; i++) - { - atts.push_back(static_cast( - mAttributeSlider[i]->getValue())); - } - -#ifdef MANASERV_SUPPORT - int characterSlot = mSlot; - // On Manaserv, the slots start at 1, so we offset them. - if (Net::getNetworkType() == ServerInfo::MANASERV) - ++characterSlot; -#else - const int characterSlot = mSlot; -#endif - - Net::getCharServerHandler()->newCharacter(getName(), characterSlot, - mFemale->isSelected(), mHairStyle, mHairColor, - static_cast(mRace), mLook, atts); - } - else - { - // TRANSLATORS: char creation error - new OkDialog(_("Error"), - // TRANSLATORS: char creation error - _("Your name needs to be at least 4 characters."), - DIALOG_ERROR, true, this); - } - } - else if (id == "cancel") - { - scheduleDelete(); - } - else if (id == "nextcolor") - { - mHairColor ++; - updateHair(); - } - else if (id == "prevcolor") - { - mHairColor --; - updateHair(); - } - else if (id == "nextstyle") - { - mHairStyle ++; - updateHair(); - } - else if (id == "prevstyle") - { - mHairStyle --; - updateHair(); - } - else if (id == "nextrace") - { - mRace ++; - updateRace(); - } - else if (id == "prevrace") - { - mRace --; - updateRace(); - } - else if (id == "nextlook") - { - mLook ++; - updateLook(); - } - else if (id == "prevlook") - { - mLook --; - updateLook(); - } - else if (id == "statslider") - { - updateSliders(); - } - else if (id == "gender") - { - if (mMale->isSelected()) - mPlayer->setGender(GENDER_MALE); - else - mPlayer->setGender(GENDER_FEMALE); - } - else if (id == "action") - { - mAction ++; - if (mAction >= 5) - mAction = 0; - updatePlayer(); - } - else if (id == "rotate") - { - mDirection ++; - if (mDirection >= 4) - mDirection = 0; - updatePlayer(); - } -} - -std::string CharCreateDialog::getName() const -{ - std::string name = mNameField->getText(); - trim(name); - return name; -} - -void CharCreateDialog::updateSliders() -{ - for (size_t i = 0, sz = mAttributeSlider.size(); i < sz; i++) - { - // Update captions - mAttributeValue[i]->setCaption( - toString(static_cast(mAttributeSlider[i]->getValue()))); - mAttributeValue[i]->adjustSize(); - } - - // Update distributed points - const int pointsLeft = mMaxPoints - getDistributedPoints(); - if (pointsLeft == 0) - { - // TRANSLATORS: char create dialog label - mAttributesLeft->setCaption(_("Character stats OK")); - mCreateButton->setEnabled(true); - } - else - { - mCreateButton->setEnabled(false); - if (pointsLeft > 0) - { - mAttributesLeft->setCaption( - // TRANSLATORS: char create dialog label - strprintf(_("Please distribute %d points"), pointsLeft)); - } - else - { - mAttributesLeft->setCaption( - // TRANSLATORS: char create dialog label - strprintf(_("Please remove %d points"), -pointsLeft)); - } - } - - mAttributesLeft->adjustSize(); -} - -void CharCreateDialog::unlock() -{ - mCreateButton->setEnabled(true); -} - -int CharCreateDialog::getDistributedPoints() const -{ - int points = 0; - - for (size_t i = 0, sz = mAttributeSlider.size(); i < sz; i++) - points += static_cast(mAttributeSlider[i]->getValue()); - return points; -} - -void CharCreateDialog::setAttributes(const StringVect &labels, - const int available, - const int min, const int max) -{ - mMaxPoints = available; - - for (unsigned i = 0; i < mAttributeLabel.size(); i++) - { - remove(mAttributeLabel[i]); - delete mAttributeLabel[i]; - mAttributeLabel[i] = nullptr; - remove(mAttributeSlider[i]); - delete mAttributeSlider[i]; - mAttributeSlider[i] = nullptr; - remove(mAttributeValue[i]); - delete mAttributeValue[i]; - mAttributeValue[i] = nullptr; - } - - mAttributeLabel.resize(labels.size()); - mAttributeSlider.resize(labels.size()); - mAttributeValue.resize(labels.size()); - - const int w = 480; - const int h = 350; - const int y = 118 + 29; - - for (unsigned i = 0, sz = static_cast(labels.size()); - i < sz; i++) - { - mAttributeLabel[i] = new Label(this, labels[i]); - mAttributeLabel[i]->setWidth(70); - mAttributeLabel[i]->setPosition(5, y + i * 24); - mAttributeLabel[i]->adjustSize(); - add(mAttributeLabel[i]); - - mAttributeSlider[i] = new Slider(min, max); - mAttributeSlider[i]->setDimension(gcn::Rectangle(140, y + i * 24, - 150, 12)); - mAttributeSlider[i]->setActionEventId("statslider"); - mAttributeSlider[i]->addActionListener(this); - add(mAttributeSlider[i]); - - mAttributeValue[i] = new Label(this, toString(min)); - mAttributeValue[i]->setPosition(295, y + i * 24); - add(mAttributeValue[i]); - } - - updateSliders(); - setButtonsPosition(w, h); -} - -void CharCreateDialog::setFixedGender(const bool fixed, const Gender gender) -{ - if (gender == GENDER_FEMALE) - { - mFemale->setSelected(true); - mMale->setSelected(false); - mOther->setSelected(false); - } - else if (gender == GENDER_MALE) - { - mFemale->setSelected(false); - mMale->setSelected(true); - mOther->setSelected(false); - } - else - { - mFemale->setSelected(false); - mMale->setSelected(false); - mOther->setSelected(true); - } - - mPlayer->setGender(gender); - - if (fixed) - { - mMale->setVisible(false); - mFemale->setVisible(false); - mOther->setVisible(false); - } -} - -void CharCreateDialog::updateHair() -{ - if (mHairStyle <= 0) - mHairStyle = Being::getNumOfHairstyles() - 1; - else - mHairStyle %= Being::getNumOfHairstyles(); - if (mHairStyle < static_cast(minHairStyle) - || mHairStyle > static_cast(maxHairStyle)) - { - mHairStyle = minHairStyle; - } - const ItemInfo &item = ItemDB::get(-mHairStyle); - mHairStyleNameLabel->setCaption(item.getName()); - mHairStyleNameLabel->adjustSize(); - - if (ColorDB::getHairSize()) - mHairColor %= ColorDB::getHairSize(); - else - mHairColor = 0; - if (mHairColor < 0) - mHairColor += ColorDB::getHairSize(); - if (mHairColor < static_cast(minHairColor) - || mHairColor > static_cast(maxHairColor)) - { - mHairColor = minHairColor; - } - mHairColorNameLabel->setCaption(ColorDB::getHairColorName(mHairColor)); - mHairColorNameLabel->adjustSize(); - - mPlayer->setSprite(Net::getCharServerHandler()->hairSprite(), - mHairStyle * -1, item.getDyeColorsString(mHairColor)); -} - -void CharCreateDialog::updateRace() -{ - if (mRace < 0) - mRace = Being::getNumOfRaces() - 1; - else if (mRace >= Being::getNumOfRaces()) - mRace = 0; - - updateLook(); -} - -void CharCreateDialog::updateLook() -{ - const ItemInfo &item = ItemDB::get(-100 - mRace); - const int sz = item.getColorsSize(); - if (sz > 0 && serverVersion >= 9) - { - if (mLook < 0) - mLook = sz - 1; - if (mLook > mMaxLook) - mLook = mMinLook; - if (mLook >= sz) - mLook = mMinLook; - } - else - { - mLook = 0; - } - mPlayer->setSubtype(static_cast(mRace), mLook); - if (mRaceNameLabel) - { - mRaceNameLabel->setCaption(item.getName()); - mRaceNameLabel->adjustSize(); - } - if (mLookNameLabel) - { - mLookNameLabel->setCaption(item.getColorName(mLook)); - mLookNameLabel->adjustSize(); - } -} - -void CharCreateDialog::logic() -{ - if (mPlayer) - mPlayer->logic(); -} - -void CharCreateDialog::updatePlayer() -{ - if (mPlayer) - { - mPlayer->setDirection(directions[mDirection]); - mPlayer->setAction(actions[mAction]); - } -} - -void CharCreateDialog::keyPressed(gcn::KeyEvent &keyEvent) -{ - const int actionId = static_cast(&keyEvent)->getActionId(); - switch (actionId) - { - case Input::KEY_GUI_CANCEL: - keyEvent.consume(); - action(gcn::ActionEvent(mCancelButton, - mCancelButton->getActionEventId())); - break; - - default: - break; - } -} - -void CharCreateDialog::setButtonsPosition(const int w, const int h) -{ - if (mainGraphics->getHeight() < 480) - { - mCreateButton->setPosition(340, 150); - mCancelButton->setPosition(340, 160 + mCreateButton->getHeight()); - } - else - { - mCancelButton->setPosition( - w / 2, - h - 5 - mCancelButton->getHeight()); - mCreateButton->setPosition( - mCancelButton->getX() - 5 - mCreateButton->getWidth(), - h - 5 - mCancelButton->getHeight()); - } - mAttributesLeft->setPosition(15, 260 + 29); -} diff --git a/src/gui/charcreatedialog.h b/src/gui/charcreatedialog.h deleted file mode 100644 index 207ac557d..000000000 --- a/src/gui/charcreatedialog.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_CHARCREATEDIALOG_H -#define GUI_CHARCREATEDIALOG_H - -#include "being/being.h" - -#include "gui/charselectdialog.h" - -#include -#include - -class Label; -class PlayerBox; -class RadioButton; -class Slider; -class TextField; - -/** - * Character creation dialog. - * - * \ingroup Interface - */ -class CharCreateDialog final : public Window, - public gcn::ActionListener, - public gcn::KeyListener -{ - public: - /** - * Constructor. - */ - CharCreateDialog(CharSelectDialog *const parent, const int slot); - - A_DELETE_COPY(CharCreateDialog) - - /** - * Destructor. - */ - ~CharCreateDialog(); - - void action(const gcn::ActionEvent &event) override; - - /** - * Unlocks the dialog, enabling the create character button again. - */ - void unlock(); - - void setAttributes(const StringVect &labels, - const int available, - const int min, const int max); - - void setFixedGender(const bool fixed, - const Gender gender = GENDER_FEMALE); - - void logic() override; - - void updatePlayer(); - - void keyPressed(gcn::KeyEvent &keyEvent) override; - - private: - int getDistributedPoints() const A_WARN_UNUSED; - - void updateSliders(); - - void setButtonsPosition(const int w, const int h); - - /** - * Returns the name of the character to create. - */ - std::string getName() const A_WARN_UNUSED; - - /** - * Communicate character creation to the server. - */ - void attemptCharCreate(); - - void updateHair(); - - void updateRace(); - - void updateLook(); - - CharSelectDialog *mCharSelectDialog; - - TextField *mNameField; - Label *mNameLabel; - Button *mNextHairColorButton; - Button *mPrevHairColorButton; - Label *mHairColorLabel; - Label *mHairColorNameLabel; - Button *mNextHairStyleButton; - Button *mPrevHairStyleButton; - Label *mHairStyleLabel; - Label *mHairStyleNameLabel; - Button *mNextRaceButton; - Button *mPrevRaceButton; - Label *mRaceLabel; - Label *mRaceNameLabel; - Button *mNextLookButton; - Button *mPrevLookButton; - Label *mLookLabel; - Label *mLookNameLabel; - - Button *mActionButton; - Button *mRotateButton; - - RadioButton *mMale; - RadioButton *mFemale; - RadioButton *mOther; - - std::vector mAttributeSlider; - std::vector mAttributeLabel; - std::vector mAttributeValue; - Label *mAttributesLeft; - - int mMaxPoints; - int mUsedPoints; - - Button *mCreateButton; - Button *mCancelButton; - - int mRace; - int mLook; - int mMinLook; - int mMaxLook; - - Being *mPlayer; - PlayerBox *mPlayerBox; - - int mHairStyle; - int mHairColor; - - int mSlot; - - unsigned maxHairColor; - unsigned minHairColor; - unsigned maxHairStyle; - unsigned minHairStyle; - - unsigned mAction; - unsigned mDirection; -}; - -#endif // GUI_CHARCREATEDIALOG_H diff --git a/src/gui/charselectdialog.cpp b/src/gui/charselectdialog.cpp deleted file mode 100644 index 1ab2bd0b0..000000000 --- a/src/gui/charselectdialog.cpp +++ /dev/null @@ -1,587 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/charselectdialog.h" - -#include "client.h" -#include "configuration.h" -#include "units.h" - -#include "input/keydata.h" -#include "input/keyevent.h" - -#include "gui/charcreatedialog.h" -#include "gui/confirmdialog.h" -#include "gui/logindialog.h" -#include "gui/okdialog.h" -#include "gui/textdialog.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/characterdisplay.h" -#include "gui/widgets/characterviewnormal.h" -#include "gui/widgets/characterviewsmall.h" -#include "gui/widgets/layout.h" - -#include "net/logindata.h" -#include "net/loginhandler.h" - -#include "utils/gettext.h" - -#include "debug.h" - -// Character slots per row in the dialog -static const int SLOTS_PER_ROW = 5; - -/** - * Listener for confirming character deletion. - */ -class CharDeleteConfirm final : public ConfirmDialog -{ - public: - CharDeleteConfirm(CharSelectDialog *const m, const int index) : - // TRANSLATORS: char deletion message - ConfirmDialog(_("Confirm Character Delete"), - // TRANSLATORS: char deletion message - _("Are you sure you want to delete this character?"), - SOUND_REQUEST, false, false, m), - mMaster(m), - mIndex(index) - { - } - - A_DELETE_COPY(CharDeleteConfirm) - - void action(const gcn::ActionEvent &event) - { - if (event.getId() == "yes" && mMaster) - mMaster->askPasswordForDeletion(mIndex); - - ConfirmDialog::action(event); - } - - private: - CharSelectDialog *mMaster; - int mIndex; -}; - -CharSelectDialog::CharSelectDialog(LoginData *const data): - // TRANSLATORS: char select dialog name - Window(strprintf(_("Account %s (last login time %s)"), - data->username.c_str(), data->lastLogin.c_str()), - false, nullptr, "char.xml"), - gcn::ActionListener(), - gcn::KeyListener(), - mLoginData(data), - // TRANSLATORS: char select dialog. button. - mSwitchLoginButton(new Button(this, _("Switch Login"), "switch", this)), - // TRANSLATORS: char select dialog. button. - mChangePasswordButton(new Button(this, _("Change Password"), - "change_password", this)), - mUnregisterButton(nullptr), - mChangeEmailButton(nullptr), - // TRANSLATORS: char select dialog. button. - mPlayButton(new Button(this, _("Play"), "use", this)), - // TRANSLATORS: char select dialog. button. - mInfoButton(new Button(this, _("Info"), "info", this)), - // TRANSLATORS: char select dialog. button. - mDeleteButton(new Button(this, _("Delete"), "delete", this)), - mCharacterView(nullptr), - mCharacterEntries(0), - mCharServerHandler(Net::getCharServerHandler()), - mDeleteDialog(nullptr), - mDeleteIndex(-1), - mLocked(false), - mSmallScreen(mainGraphics->getWidth() < 470 - || mainGraphics->getHeight() < 370) -{ - setCloseButton(true); - setFocusable(true); - - const int optionalActions = Net::getLoginHandler() - ->supportedOptionalActions(); - - ContainerPlacer placer; - placer = getPlacer(0, 0); - - placer(0, 0, mSwitchLoginButton); - - int n = 1; - if (optionalActions & Net::LoginHandler::Unregister) - { - // TRANSLATORS: char select dialog. button. - mUnregisterButton = new Button(this, _("Unregister"), - "unregister", this); - placer(n, 0, mUnregisterButton); - n ++; - } - - placer(n, 0, mChangePasswordButton); - n ++; - - if (optionalActions & Net::LoginHandler::ChangeEmail) - { - // TRANSLATORS: char select dialog. button. - mChangeEmailButton = new Button(this, _("Change Email"), - "change_email", this); - placer(n, 0, mChangeEmailButton); - n ++; - } - - placer(n, 0, mDeleteButton); - n ++; - placer(n, 0, mInfoButton); - n ++; - - for (int i = 0; i < static_cast(mLoginData->characterSlots); i++) - { - CharacterDisplay *const character = new CharacterDisplay(this, this); - character->setVisible(false); - mCharacterEntries.push_back(character); - } - - placer(0, 2, mPlayButton); - - if (!mSmallScreen) - { - mCharacterView = new CharacterViewNormal( - this, &mCharacterEntries, mPadding); - placer(0, 1, mCharacterView, 10); - int sz = 410 + 2 * mPadding; - if (config.getIntValue("fontSize") > 18) - sz = 500 + 2 * mPadding; - const int width = mCharacterView->getWidth() + 2 * mPadding; - if (sz < width) - sz = width; - if (sz > mainGraphics->getWidth()) - sz = mainGraphics->getWidth(); - reflowLayout(sz); - } - else - { - // TRANSLATORS: char select dialog name - setCaption(strprintf(_("Account %s"), mLoginData->username.c_str())); - mCharacterView = new CharacterViewSmall( - this, &mCharacterEntries, mPadding); - mCharacterView->setWidth(mainGraphics->getWidth() - - 2 * getPadding()); - placer(0, 1, mCharacterView, 10); - reflowLayout(); - } - addKeyListener(this); - center(); - setVisible(true); - requestFocus(); - - Net::getCharServerHandler()->setCharSelectDialog(this); - mCharacterView->show(0); - updateState(); -} - -CharSelectDialog::~CharSelectDialog() -{ -} - -void CharSelectDialog::action(const gcn::ActionEvent &event) -{ - // Check if a button of a character was pressed - const gcn::Widget *const sourceParent = event.getSource()->getParent(); - int selected = -1; - for (unsigned int i = 0, sz = static_cast( - mCharacterEntries.size()); i < sz; ++i) - { - if (mCharacterEntries[i] == sourceParent) - { - selected = i; - mCharacterView->show(i); - updateState(); - break; - } - } - if (selected == -1) - selected = mCharacterView->getSelected(); - - const std::string &eventId = event.getId(); - - if (selected >= 0) - { - if (eventId == "use") - { - use(selected); - return; - } - else if (eventId == "delete" - && mCharacterEntries[selected]->getCharacter()) - { - new CharDeleteConfirm(this, selected); - return; - } - else if (eventId == "info") - { - Net::Character *const character = mCharacterEntries[ - selected]->getCharacter(); - if (!character) - return; - - const LocalPlayer *const data = character->dummy; - if (!data) - return; - - const std::string msg = strprintf( - // TRANSLATORS: char select dialog. player info message. - _("Hp: %u/%u\nMp: %u/%u\nLevel: %u\n" - "Experience: %u\nMoney: %s"), - character->data.mAttributes[PlayerInfo::HP], - character->data.mAttributes[PlayerInfo::MAX_HP], - character->data.mAttributes[PlayerInfo::MP], - character->data.mAttributes[PlayerInfo::MAX_MP], - character->data.mAttributes[PlayerInfo::LEVEL], - character->data.mAttributes[PlayerInfo::EXP], - Units::formatCurrency( - character->data.mAttributes[PlayerInfo::MONEY]).c_str()); - new OkDialog(data->getName(), msg, DIALOG_SILENCE); - } - } - if (eventId == "switch") - { - Net::getCharServerHandler()->clear(); - close(); - } - else if (eventId == "change_password") - { - client->setState(STATE_CHANGEPASSWORD); - } - else if (eventId == "change_email") - { - client->setState(STATE_CHANGEEMAIL); - } - else if (eventId == "unregister") - { - Net::getCharServerHandler()->clear(); - client->setState(STATE_UNREGISTER); - } - else if (eventId == "try delete character") - { - if (mDeleteDialog && mDeleteIndex != -1 && mDeleteDialog->getText() - == LoginDialog::savedPassword) - { - attemptCharacterDelete(mDeleteIndex); - mDeleteDialog = nullptr; - } - else - { - // TRANSLATORS: error message - new OkDialog(_("Error"), _("Incorrect password"), DIALOG_ERROR); - } - mDeleteIndex = -1; - } -} - -void CharSelectDialog::use(const int selected) -{ - if (mCharacterEntries[selected] - && mCharacterEntries[selected]->getCharacter()) - { - attemptCharacterSelect(selected); - } - else - { - CharCreateDialog *const charCreateDialog = - new CharCreateDialog(this, selected); - mCharServerHandler->setCharCreateDialog(charCreateDialog); - } -} - -void CharSelectDialog::keyPressed(gcn::KeyEvent &keyEvent) -{ - const int actionId = static_cast(&keyEvent)->getActionId(); - switch (actionId) - { - case Input::KEY_GUI_CANCEL: - keyEvent.consume(); - action(gcn::ActionEvent(mSwitchLoginButton, - mSwitchLoginButton->getActionEventId())); - break; - - case Input::KEY_GUI_RIGHT: - { - keyEvent.consume(); - int idx = mCharacterView->getSelected(); - if (idx >= 0) - { - idx ++; - if (idx == SLOTS_PER_ROW) - break; - mCharacterView->show(idx); - updateState(); - } - break; - } - - case Input::KEY_GUI_LEFT: - { - keyEvent.consume(); - int idx = mCharacterView->getSelected(); - if (idx >= 0) - { - if (!idx || idx == SLOTS_PER_ROW) - break; - idx --; - mCharacterView->show(idx); - updateState(); - } - break; - } - - case Input::KEY_GUI_UP: - { - keyEvent.consume(); - int idx = mCharacterView->getSelected(); - if (idx >= 0) - { - if (idx < SLOTS_PER_ROW) - break; - idx -= SLOTS_PER_ROW; - mCharacterView->show(idx); - updateState(); - } - break; - } - - case Input::KEY_GUI_DOWN: - { - keyEvent.consume(); - int idx = mCharacterView->getSelected(); - if (idx >= 0) - { - if (idx >= SLOTS_PER_ROW) - break; - idx += SLOTS_PER_ROW; - mCharacterView->show(idx); - updateState(); - } - break; - } - - case Input::KEY_GUI_DELETE: - { - keyEvent.consume(); - const int idx = mCharacterView->getSelected(); - if (idx >= 0 && mCharacterEntries[idx] - && mCharacterEntries[idx]->getCharacter()) - { - new CharDeleteConfirm(this, idx); - } - break; - } - - case Input::KEY_GUI_SELECT: - { - keyEvent.consume(); - use(mCharacterView->getSelected()); - break; - } - default: - break; - } -} - -/** - * Communicate character deletion to the server. - */ -void CharSelectDialog::attemptCharacterDelete(const int index) -{ - if (mLocked) - return; - - if (mCharacterEntries[index]) - { - mCharServerHandler->deleteCharacter( - mCharacterEntries[index]->getCharacter()); - } - lock(); -} - -void CharSelectDialog::askPasswordForDeletion(const int index) -{ - mDeleteIndex = index; - mDeleteDialog = new TextDialog( - // TRANSLATORS: char deletion question. - _("Enter password for deleting character"), _("Enter password:"), - this, true); - mDeleteDialog->setActionEventId("try delete character"); - mDeleteDialog->addActionListener(this); -} - -/** - * Communicate character selection to the server. - */ -void CharSelectDialog::attemptCharacterSelect(const int index) -{ - if (mLocked || !mCharacterEntries[index]) - return; - - setVisible(false); - if (mCharServerHandler) - { - mCharServerHandler->chooseCharacter( - mCharacterEntries[index]->getCharacter()); - } - lock(); -} - -void CharSelectDialog::setCharacters(const Net::Characters &characters) -{ - // Reset previous characters - FOR_EACH (std::vector::const_iterator, - iter, mCharacterEntries) - { - if (*iter) - (*iter)->setCharacter(nullptr); - } - - FOR_EACH (Net::Characters::const_iterator, i, characters) - { - if (!*i) - continue; - - Net::Character *const character = *i; - - // Slots Number start at 1 for Manaserv, so we offset them by one. -#ifdef MANASERV_SUPPORT - int characterSlot = character->slot; - if (Net::getNetworkType() == ServerInfo::MANASERV && characterSlot > 0) - --characterSlot; -#else - const int characterSlot = character->slot; -#endif - - if (characterSlot >= static_cast(mCharacterEntries.size())) - { - logger->log("Warning: slot out of range: %d", character->slot); - continue; - } - - if (mCharacterEntries[characterSlot]) - mCharacterEntries[characterSlot]->setCharacter(character); - } - - updateState(); -} - -void CharSelectDialog::lock() -{ - if (!mLocked) - setLocked(true); -} - -void CharSelectDialog::unlock() -{ - setLocked(false); -} - -void CharSelectDialog::setLocked(const bool locked) -{ - mLocked = locked; - - if (mSwitchLoginButton) - mSwitchLoginButton->setEnabled(!locked); - if (mChangePasswordButton) - mChangePasswordButton->setEnabled(!locked); - if (mUnregisterButton) - mUnregisterButton->setEnabled(!locked); - if (mChangeEmailButton) - mChangeEmailButton->setEnabled(!locked); - if (mPlayButton) - mPlayButton->setEnabled(!locked); - if (mDeleteButton) - mDeleteButton->setEnabled(!locked); - - for (size_t i = 0, sz = mCharacterEntries.size(); i < sz; ++i) - { - if (mCharacterEntries[i]) - mCharacterEntries[i]->setActive(!mLocked); - } -} - -bool CharSelectDialog::selectByName(const std::string &name, - const SelectAction selAction) -{ - if (mLocked) - return false; - - for (size_t i = 0, sz = mCharacterEntries.size(); i < sz; ++i) - { - if (mCharacterEntries[i]) - { - const Net::Character *const character - = mCharacterEntries[i]->getCharacter(); - if (character) - { - if (character->dummy && character->dummy->getName() == name) - { - mCharacterView->show(static_cast(i)); - updateState(); - if (selAction == Choose) - attemptCharacterSelect(static_cast(i)); - return true; - } - } - } - } - - return false; -} - -void CharSelectDialog::close() -{ - client->setState(STATE_SWITCH_LOGIN); - Window::close(); -} - -void CharSelectDialog::widgetResized(const gcn::Event &event) -{ - Window::widgetResized(event); - if (mCharacterView) - mCharacterView->resize(); -} - -void CharSelectDialog::updateState() -{ - const int idx = mCharacterView->getSelected(); - if (idx == -1) - { - mPlayButton->setEnabled(false); - return; - } - mPlayButton->setEnabled(true); - - if (mCharacterEntries[idx] && mCharacterEntries[idx]->getCharacter()) - { - // TRANSLATORS: char select dialog. button. - mPlayButton->setCaption(_("Play")); - } - else - { - // TRANSLATORS: char select dialog. button. - mPlayButton->setCaption(_("Create")); - } -} diff --git a/src/gui/charselectdialog.h b/src/gui/charselectdialog.h deleted file mode 100644 index 9556ba633..000000000 --- a/src/gui/charselectdialog.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_CHARSELECTDIALOG_H -#define GUI_CHARSELECTDIALOG_H - -#include "main.h" - -#include "gui/widgets/window.h" - -#include "net/charserverhandler.h" - -#include -#include - -class Button; -class CharacterDisplay; -class CharacterViewBase; -class Label; -class LoginData; -class TextDialog; - -/** - * Character selection dialog. - * - * \ingroup Interface - */ -class CharSelectDialog final : public Window, - public gcn::ActionListener, - public gcn::KeyListener -{ - public: - friend class CharDeleteConfirm; - friend class Net::CharServerHandler; - - /** - * Constructor. - */ - explicit CharSelectDialog(LoginData *const data); - - A_DELETE_COPY(CharSelectDialog) - - ~CharSelectDialog(); - - void action(const gcn::ActionEvent &event) override; - - void keyPressed(gcn::KeyEvent &keyEvent) override; - - enum SelectAction - { - Focus = 0, - Choose - }; - - /** - * Attempt to select the character with the given name. Returns whether - * a character with the given name was found. - * - * \param action determines what to do when a character with the given - * name was found (just focus or also try to choose this - * character). - */ - bool selectByName(const std::string &name, - const SelectAction action = Focus); - - void askPasswordForDeletion(const int index); - - void close() override; - - void widgetResized(const gcn::Event &event) override; - - void updateState(); - - private: - void attemptCharacterDelete(const int index); - - void attemptCharacterSelect(const int index); - - void setCharacters(const Net::Characters &characters); - - void use(const int selected); - - void lock(); - void unlock(); - void setLocked(const bool locked); - - LoginData *mLoginData; - - Button *mSwitchLoginButton; - Button *mChangePasswordButton; - Button *mUnregisterButton; - Button *mChangeEmailButton; - Button *mPlayButton; - Button *mInfoButton; - Button *mDeleteButton; - CharacterViewBase *mCharacterView; - - std::vector mCharacterEntries; - - Net::CharServerHandler *mCharServerHandler; - TextDialog *mDeleteDialog; - int mDeleteIndex; - bool mLocked; - bool mSmallScreen; -}; - -#endif // GUI_CHARSELECTDIALOG_H diff --git a/src/gui/chatwindow.cpp b/src/gui/chatwindow.cpp deleted file mode 100644 index 1f3ff51bb..000000000 --- a/src/gui/chatwindow.cpp +++ /dev/null @@ -1,1794 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/chatwindow.h" - -#include "actorspritemanager.h" -#include "client.h" -#include "commandhandler.h" -#include "configuration.h" -#include "game.h" -#include "guild.h" -#include "party.h" -#include "spellshortcut.h" - -#include "being/localplayer.h" -#include "being/playerinfo.h" -#include "being/playerrelations.h" - -#include "input/inputmanager.h" -#include "input/keyevent.h" - -#include "gui/emotewindow.h" -#include "gui/gui.h" -#include "gui/setup.h" -#include "gui/sdlfont.h" -#include "gui/sdlinput.h" -#include "gui/viewport.h" -#include "gui/whoisonline.h" - -#include "gui/widgets/battletab.h" -#include "gui/widgets/dropdown.h" -#include "gui/widgets/itemlinkhandler.h" -#include "gui/widgets/langtab.h" -#include "gui/widgets/scrollarea.h" -#include "gui/widgets/textfield.h" -#include "gui/widgets/tradetab.h" -#include "gui/widgets/whispertab.h" - -#include "net/chathandler.h" -#include "net/playerhandler.h" -#include "net/net.h" - -#include "utils/copynpaste.h" -#include "utils/gettext.h" - -#include "resources/resourcemanager.h" - -#include - -#include - -#include - -#include "debug.h" - -/** - * The chat input hides when it loses focus. It is also invisible by default. - */ -class ChatInput final : public TextField -{ - public: - explicit ChatInput(ChatWindow *const window): - TextField(window, "", false), - mWindow(window), - mFocusGaining(false) - { - setVisible(false); - addFocusListener(this); - } - - A_DELETE_COPY(ChatInput) - - /** - * Called if the chat input loses focus. It will set itself to - * invisible as result. - */ - void focusLost(const gcn::Event &event) - { - TextField::focusLost(event); - if (mFocusGaining || !config.getBoolValue("protectChatFocus")) - { - processVisible(false); - if (chatWindow) - chatWindow->updateVisibility(); - mFocusGaining = false; - return; - } - mFocusGaining = true; - requestFocus(); - mFocusGaining = false; - } - - void processVisible(const bool n) - { - if (!mWindow || isVisible() == n) - return; - - if (!n) - mFocusGaining = true; - setVisible(n); - if (config.getBoolValue("hideChatInput")) - mWindow->adjustTabSize(); - if (emoteWindow) - emoteWindow->hide(); - } - - void unprotectFocus() - { mFocusGaining = true; } - - void setVisible(bool visible) - { - TextField::setVisible(visible); - } - - private: - ChatWindow *mWindow; - bool mFocusGaining; -}; - -const char *COLOR_NAME[14] = -{ - // TRANSLATORS: chat color - N_("default"), - // TRANSLATORS: chat color - N_("black"), - // TRANSLATORS: chat color - N_("red"), - // TRANSLATORS: chat color - N_("green"), - // TRANSLATORS: chat color - N_("blue"), - // TRANSLATORS: chat color - N_("gold"), - // TRANSLATORS: chat color - N_("yellow"), - // TRANSLATORS: chat color - N_("pink"), - // TRANSLATORS: chat color - N_("purple"), - // TRANSLATORS: chat color - N_("grey"), - // TRANSLATORS: chat color - N_("brown"), - // TRANSLATORS: chat color - N_("rainbow 1"), - // TRANSLATORS: chat color - N_("rainbow 2"), - // TRANSLATORS: chat color - N_("rainbow 3"), -}; - - -class ColorListModel final : public gcn::ListModel -{ -public: - ~ColorListModel() - { } - - int getNumberOfElements() - { - return 14; - } - - std::string getElementAt(int i) - { - if (i >= getNumberOfElements() || i < 0) - return "???"; - return gettext(COLOR_NAME[i]); - } -}; - -static const char *const ACTION_COLOR_PICKER = "color picker"; - -ChatWindow::ChatWindow(): - // TRANSLATORS: chat window name - Window(_("Chat"), false, nullptr, "chat.xml"), - gcn::ActionListener(), - gcn::KeyListener(), - mItemLinkHandler(new ItemLinkHandler), - mChatTabs(new TabbedArea(this)), - mChatInput(new ChatInput(this)), - mRainbowColor(0), - mWhispers(), - mHistory(), - mCurHist(), - mCommands(), - mCustomWords(), - mReturnToggles(config.getBoolValue("ReturnToggles")), - mTradeFilter(), - mColorListModel(new ColorListModel), - mColorPicker(new DropDown(this, mColorListModel)), - mChatColor(config.getIntValue("chatColor")), - mChatHistoryIndex(0), - mAwayLog(), - mHighlights(), - mGlobalsFilter(), - mGMLoaded(false), - mHaveMouse(false), - mAutoHide(config.getBoolValue("autohideChat")), - mShowBattleEvents(config.getBoolValue("showBattleEvents")), - mShowAllLang(serverConfig.getValue("showAllLang", 0)), - mTmpVisible(false) -{ - listen(CHANNEL_ATTRIBUTES); - - setWindowName("Chat"); - - if (setupWindow) - setupWindow->registerWindowForReset(this); - - setShowTitle(false); - setResizable(true); - setDefaultVisible(true); - setSaveVisible(true); - setStickyButtonLock(true); - - int w = 600; -#ifdef ANDROID - if (mainGraphics->getWidth() < 710) - w = mainGraphics->getWidth() - 110; - if (w < 100) - w = 100; - if (mainGraphics->getHeight() < 480) - setDefaultSize(w, 90, ImageRect::UPPER_LEFT, -110, -35); - else - setDefaultSize(w, 123, ImageRect::UPPER_LEFT, -110, -35); -#else - if (mainGraphics->getWidth() < 600) - w = mainGraphics->getWidth() - 10; - if (w < 100) - w = 100; - setDefaultSize(w, 123, ImageRect::LOWER_LEFT); -#endif - setMinWidth(150); - setMinHeight(90); - - setTitleBarHeight(getPadding() + getTitlePadding()); - - if (emoteWindow) - emoteWindow->addListeners(this); - - mChatTabs->enableScrollButtons(true); - mChatTabs->setFollowDownScroll(true); - mChatTabs->setResizeHeight(false); - - mChatInput->setActionEventId("chatinput"); - mChatInput->addActionListener(this); - - mColorPicker->setActionEventId(ACTION_COLOR_PICKER); - mColorPicker->addActionListener(this); - mColorPicker->setSelected(mChatColor); - - add(mChatTabs); - add(mChatInput); - add(mColorPicker); - - loadWindowState(); - - mColorPicker->setPosition(this->getWidth() - mColorPicker->getWidth() - - 2 * mPadding - 8 - 16, mPadding); - - // Add key listener to chat input to be able to respond to up/down - mChatInput->addKeyListener(this); - mCurHist = mHistory.end(); - mColorPicker->setVisible(config.getBoolValue("showChatColorsList")); - - fillCommands(); - if (player_node && player_node->isGM()) - loadGMCommands(); - initTradeFilter(); - loadCustomList(); - parseHighlights(); - parseGlobalsFilter(); - - config.addListener("autohideChat", this); - config.addListener("showBattleEvents", this); - config.addListener("globalsFilter", this); - - enableVisibleSound(true); -} - -ChatWindow::~ChatWindow() -{ - config.removeListeners(this); - saveState(); - config.setValue("ReturnToggles", mReturnToggles); - removeAllWhispers(); - delete mItemLinkHandler; - mItemLinkHandler = nullptr; - delete mColorPicker; - mColorPicker = nullptr; - delete mColorListModel; - mColorListModel = nullptr; -} - -void ChatWindow::loadCommandsFile(const std::string &name) -{ - StringVect list; - ResourceManager::loadTextFile(name, list); - StringVectCIter it = list.begin(); - const StringVectCIter it_end = list.end(); - - while (it != it_end) - { - const std::string str = *it; - if (!str.empty()) - mCommands.push_back(str); - ++ it; - } -} - -void ChatWindow::fillCommands() -{ - loadCommandsFile("chatcommands.txt"); - CommandHandler::addChatCommands(mCommands); -} - -void ChatWindow::loadGMCommands() -{ - if (mGMLoaded) - return; - - loadCommandsFile("gmcommands.txt"); - mGMLoaded = true; -} - -void ChatWindow::adjustTabSize() -{ - const gcn::Rectangle area = getChildrenArea(); - - const int aw = area.width; - const int ah = area.height; - const int frame = mChatInput->getFrameSize(); - const int inputHeight = mChatInput->getHeight(); - const int frame2 = 2 * frame; - const int awFrame2 = aw - frame2; - mChatInput->setPosition(frame, ah - inputHeight - frame); - mChatInput->setWidth(awFrame2); - mChatTabs->setWidth(awFrame2); - const int height = ah - frame2 - (inputHeight + frame2); - if (mChatInput->isVisible() || !config.getBoolValue("hideChatInput")) - mChatTabs->setHeight(height); - else - mChatTabs->setHeight(height + inputHeight); - - const ChatTab *const tab = getFocused(); - if (tab) - { - gcn::Widget *const content = tab->mScrollArea; - if (content) - { - const int contentFrame2 = 2 * content->getFrameSize(); - content->setSize(mChatTabs->getWidth() - contentFrame2, - mChatTabs->getContainerHeight() - contentFrame2); - content->logic(); - } - } - - mColorPicker->setPosition(this->getWidth() - mColorPicker->getWidth() - - 2 * mPadding - 8 - 16, mPadding); - - mChatTabs->adjustSize(); -} - -void ChatWindow::widgetResized(const gcn::Event &event) -{ - Window::widgetResized(event); - - adjustTabSize(); -} - -ChatTab *ChatWindow::getFocused() const -{ - return static_cast(mChatTabs->getSelectedTab()); -} - -void ChatWindow::clearTab(ChatTab *const tab) const -{ - if (tab) - tab->clearText(); -} - -void ChatWindow::clearTab() const -{ - clearTab(getFocused()); -} - -void ChatWindow::prevTab() -{ - if (!mChatTabs) - return; - - int tab = mChatTabs->getSelectedTabIndex(); - - if (tab <= 0) - tab = mChatTabs->getNumberOfTabs(); - tab--; - - mChatTabs->setSelectedTabByPos(tab); -} - -void ChatWindow::nextTab() -{ - if (!mChatTabs) - return; - - int tab = mChatTabs->getSelectedTabIndex(); - - tab++; - if (tab == mChatTabs->getNumberOfTabs()) - tab = 0; - - mChatTabs->setSelectedTabByPos(tab); -} - -void ChatWindow::closeTab() const -{ - if (!mChatTabs) - return; - - Tab *const tab = mChatTabs->getTabByIndex( - mChatTabs->getSelectedTabIndex()); - if (!tab) - return; - WhisperTab *const whisper = dynamic_cast(tab); - if (!whisper) - return; - - whisper->handleCommand("close", ""); -} - -void ChatWindow::defaultTab() -{ - if (mChatTabs) - mChatTabs->setSelectedTabByPos(static_cast(0)); -} - -void ChatWindow::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "chatinput") - { - std::string message = mChatInput->getText(); - - if (!message.empty()) - { - // If message different from previous, put it in the history - if (mHistory.empty() || message != mHistory.back()) - mHistory.push_back(message); - - // Reset history iterator - mCurHist = mHistory.end(); - - // Send the message to the server - chatInput(addColors(message)); - - // Clear the text from the chat input - mChatInput->setText(""); - } - - if (message.empty() || !mReturnToggles) - { - // Remove focus and hide input - mChatInput->unprotectFocus(); - if (mFocusHandler) - mFocusHandler->focusNone(); - - // If the chatWindow is shown up because you want to send a message - // It should hide now - if (mTmpVisible) - setVisible(false); - } - } - else if (eventId == "emote") - { - if (emoteWindow) - { - const std::string str = emoteWindow->getSelectedEmote(); - if (!str.empty()) - { - addInputText(str, false); - emoteWindow->clearEmote(); - } - } - } - else if (eventId == "color") - { - if (emoteWindow) - { - const std::string str = emoteWindow->getSelectedColor(); - if (!str.empty()) - { - addInputText(str, false); - emoteWindow->clearColor(); - } - } - } - else if (eventId == "font") - { - if (emoteWindow) - { - const std::string str = emoteWindow->getSelectedFont(); - if (!str.empty()) - { - addInputText(str, false); - emoteWindow->clearFont(); - } - } - } - else if (eventId == ACTION_COLOR_PICKER) - { - if (mColorPicker) - { - mChatColor = mColorPicker->getSelected(); - config.setValue("chatColor", mChatColor); - } - } - - if (mColorPicker && mColorPicker->isVisible() - != config.getBoolValue("showChatColorsList")) - { - mColorPicker->setVisible(config.getBoolValue( - "showChatColorsList")); - } -} - -bool ChatWindow::requestChatFocus() -{ - // Make sure chatWindow is visible - if (!isWindowVisible()) - { - setVisible(true); - - /* - * This is used to hide chatWindow after sending the message. There is - * a trick here, because setVisible will set mTmpVisible to false, you - * have to put this sentence *after* setVisible, not before it - */ - mTmpVisible = true; - } - - // Don't do anything else if the input is already visible and has focus - if (mChatInput->isVisible() && mChatInput->isFocused()) - return false; - - // Give focus to the chat input - mChatInput->processVisible(true); - unHideWindow(); - mChatInput->requestFocus(); - return true; -} - -bool ChatWindow::isInputFocused() const -{ - return mChatInput->isFocused(); -} - -void ChatWindow::removeTab(ChatTab *const tab) -{ - mChatTabs->removeTab(tab); -} - -void ChatWindow::addTab(ChatTab *const tab) -{ - if (!tab) - return; - - mChatTabs->addTab(tab, tab->mScrollArea); - logic(); -} - -void ChatWindow::removeWhisper(const std::string &nick) -{ - std::string tempNick = nick; - toLower(tempNick); - mWhispers.erase(tempNick); -} - -void ChatWindow::removeAllWhispers() -{ - std::list tabs; - - FOR_EACH (TabMap::iterator, iter, mWhispers) - tabs.push_back(iter->second); - - for (std::list::iterator it = tabs.begin(); - it != tabs.end(); ++it) - { - delete *it; - } - - mWhispers.clear(); -} - -void ChatWindow::ignoreAllWhispers() -{ - for (TabMap::iterator iter = mWhispers.begin(); - iter != mWhispers.end(); - ++ iter) - { - const WhisperTab *const tab = dynamic_cast( - iter->second); - if (tab && player_relations.getRelation(tab->getNick()) - != PlayerRelation::IGNORED) - { - player_relations.setRelation(tab->getNick(), - PlayerRelation::IGNORED); - } - - delete (iter->second); - iter->second = nullptr; - } -} - -void ChatWindow::chatInput(const std::string &message) const -{ - ChatTab *tab = nullptr; - std::string msg = message; - trim(msg); - - if (config.getBoolValue("allowCommandsInChatTabs") - && msg.length() > 1 - && ((msg.at(0) == '#' && msg.at(1) != '#') || msg.at(0) == '@') - && localChatTab) - { - tab = localChatTab; - } - else - { - tab = getFocused(); - } - if (tab) - tab->chatInput(msg); - Game::instance()->setValidSpeed(); -} - -void ChatWindow::localChatInput(const std::string &msg) const -{ - if (localChatTab) - localChatTab->chatInput(msg); - else - chatInput(msg); -} - -void ChatWindow::doPresent() const -{ - if (!actorSpriteManager) - return; - - const ActorSprites &actors = actorSpriteManager->getAll(); - std::string response; - int playercount = 0; - - FOR_EACH (ActorSpritesConstIterator, it, actors) - { - if ((*it)->getType() == ActorSprite::PLAYER) - { - if (!response.empty()) - response.append(", "); - response.append(static_cast(*it)->getName()); - playercount ++; - } - } - - const std::string log = strprintf( - // TRANSLATORS: chat message - _("Present: %s; %d players are present."), - response.c_str(), playercount); - - if (getFocused()) - getFocused()->chatLog(log, BY_SERVER); -} - -void ChatWindow::scroll(const int amount) const -{ - if (!isWindowVisible()) - return; - - ChatTab *const tab = getFocused(); - if (tab) - tab->scroll(amount); -} - -void ChatWindow::mousePressed(gcn::MouseEvent &event) -{ - if (event.isConsumed()) - return; - - if (event.getButton() == gcn::MouseEvent::RIGHT) - { - if (viewport) - { - Tab *const tab = mChatTabs->getSelectedTab(); - if (tab) - { - if (inputManager.isActionActive(static_cast( - Input::KEY_CHAT_MOD))) - { - ChatTab *const wTab = dynamic_cast(tab); - if (wTab) - wTab->handleCommand("close", ""); - } - else - { - ChatTab *const cTab = dynamic_cast(tab); - if (cTab) - viewport->showChatPopup(cTab); - } - } - } - } - - Window::mousePressed(event); - - if (event.isConsumed()) - return; - - if (event.getButton() == gcn::MouseEvent::LEFT) - { - const ChatTab *const tab = getFocused(); - if (tab) - mMoved = !isResizeAllowed(event); - } - - mDragOffsetX = event.getX(); - mDragOffsetY = event.getY(); -} - -void ChatWindow::mouseDragged(gcn::MouseEvent &event) -{ - Window::mouseDragged(event); - - if (event.isConsumed()) - return; - - if (canMove() && isMovable() && mMoved) - { - int newX = std::max(0, getX() + event.getX() - mDragOffsetX); - int newY = std::max(0, getY() + event.getY() - mDragOffsetY); - newX = std::min(mainGraphics->mWidth - getWidth(), newX); - newY = std::min(mainGraphics->mHeight - getHeight(), newY); - setPosition(newX, newY); - } -} - -#define caseKey(key, str) case key:\ - temp = str; \ - break - -void ChatWindow::keyPressed(gcn::KeyEvent &event) -{ - const int key = event.getKey().getValue(); - const int actionId = static_cast(&event)->getActionId(); - if (actionId == static_cast(Input::KEY_GUI_DOWN)) - { - if (mCurHist != mHistory.end()) - { - // Move forward through the history - const HistoryIterator prevHist = mCurHist++; - - if (mCurHist != mHistory.end()) - { - mChatInput->setText(*mCurHist); - mChatInput->setCaretPosition(static_cast( - mChatInput->getText().length())); - } - else - { - mChatInput->setText(""); - mCurHist = prevHist; - } - } - else if (!mChatInput->getText().empty()) - { - mChatInput->setText(""); - } - } - else if (actionId == static_cast(Input::KEY_GUI_UP) && - mCurHist != mHistory.begin() && !mHistory.empty()) - { - // Move backward through the history - --mCurHist; - mChatInput->setText(*mCurHist); - mChatInput->setCaretPosition(static_cast( - mChatInput->getText().length())); - } - else if (actionId == static_cast(Input::KEY_GUI_INSERT) && - mChatInput->getText() != "") - { - // Add the current message to the history and clear the text - if (mHistory.empty() || mChatInput->getText() != mHistory.back()) - mHistory.push_back(mChatInput->getText()); - mCurHist = mHistory.end(); - mChatInput->setText(""); - } - else if (actionId == static_cast(Input::KEY_GUI_TAB) && - !mChatInput->getText().empty()) - { - autoComplete(); - return; - } - else if (actionId == static_cast(Input::KEY_GUI_CANCEL) && - mChatInput->isVisible()) - { - mChatInput->processVisible(false); - } - else if (actionId == static_cast(Input::KEY_CHAT_PREV_HISTORY) && - mChatInput->isVisible()) - { - const ChatTab *const tab = getFocused(); - if (tab && tab->hasRows()) - { - if (!mChatHistoryIndex) - { - mChatHistoryIndex = static_cast( - tab->getRows().size()); - - mChatInput->setText(""); - mChatInput->setCaretPosition(0); - return; - } - else - { - mChatHistoryIndex --; - } - - unsigned int f = 0; - const std::list &rows = tab->getRows(); - for (std::list::const_iterator it = rows.begin(), - it_end = rows.end(); it != it_end; ++ it, f ++) - { - if (f == mChatHistoryIndex) - mChatInput->setText(*it); - } - mChatInput->setCaretPosition(static_cast( - mChatInput->getText().length())); - } - } - else if (actionId == static_cast(Input::KEY_CHAT_NEXT_HISTORY) && - mChatInput->isVisible()) - { - const ChatTab *const tab = getFocused(); - if (tab && tab->hasRows()) - { - const std::list &rows = tab->getRows(); - const size_t &tabSize = rows.size(); - if (mChatHistoryIndex + 1 < tabSize) - { - mChatHistoryIndex ++; - } - else if (mChatHistoryIndex < tabSize) - { - mChatHistoryIndex ++; - mChatInput->setText(""); - mChatInput->setCaretPosition(0); - return; - } - else - { - mChatHistoryIndex = 0; - } - - unsigned int f = 0; - for (std::list::const_iterator - it = rows.begin(), it_end = rows.end(); - it != it_end; ++it, f++) - { - if (f == mChatHistoryIndex) - mChatInput->setText(*it); - } - mChatInput->setCaretPosition(static_cast( - mChatInput->getText().length())); - } - } - - std::string temp; - switch (key) - { - case Key::F1: - if (emoteWindow) - emoteWindow->show(); - break; - caseKey(Key::F2, "\u2318"); - caseKey(Key::F3, "\u263A"); - caseKey(Key::F4, "\u2665"); - caseKey(Key::F5, "\u266A"); - caseKey(Key::F6, "\u266B"); - caseKey(Key::F7, "\u26A0"); - caseKey(Key::F8, "\u2622"); - caseKey(Key::F9, "\u262E"); - caseKey(Key::F10, "\u2605"); - caseKey(Key::F11, "\u2618"); - caseKey(Key::F12, "\u2592"); - default: - break; - } - - if (!temp.empty()) - addInputText(temp, false); -} - -void ChatWindow::processEvent(const Channels channel, - const DepricatedEvent &event) -{ - if (channel == CHANNEL_ATTRIBUTES) - { - if (!mShowBattleEvents) - return; - - if (event.getName() == EVENT_UPDATEATTRIBUTE) - { - switch (event.getInt("id")) - { - case PlayerInfo::EXP: - { - if (event.getInt("oldValue") > event.getInt("newValue")) - break; - - const int change = event.getInt("newValue") - - event.getInt("oldValue"); - - if (change != 0) - { - battleChatLog(std::string("+").append(toString( - change)).append(" xp")); - } - break; - } - case PlayerInfo::LEVEL: - battleChatLog(std::string("Level: ").append(toString( - event.getInt("newValue")))); - break; - default: - break; - }; - } - else if (event.getName() == EVENT_UPDATESTAT) - { - if (!config.getBoolValue("showJobExp")) - return; - - const int id = event.getInt("id"); - if (id == Net::getPlayerHandler()->getJobLocation()) - { - const std::pair exp - = PlayerInfo::getStatExperience(id); - if (event.getInt("oldValue1") > exp.first - || !event.getInt("oldValue2")) - { - return; - } - - const int change = exp.first - event.getInt("oldValue1"); - if (change != 0) - { - battleChatLog(std::string("+").append( - toString(change)).append(" job")); - } - } - } - } -} - -void ChatWindow::addInputText(const std::string &text, const bool space) -{ - const int caretPos = mChatInput->getCaretPosition(); - const std::string inputText = mChatInput->getText(); - - std::ostringstream ss; - ss << inputText.substr(0, caretPos) << text; - if (space) - ss << " "; - - ss << inputText.substr(caretPos); - mChatInput->setText(ss.str()); - mChatInput->setCaretPosition(caretPos + static_cast( - text.length()) + static_cast(space)); - requestChatFocus(); -} - -void ChatWindow::addItemText(const std::string &item) -{ - std::ostringstream text; - text << "[" << item << "]"; - addInputText(text.str()); -} - -void ChatWindow::setVisible(bool visible) -{ - Window::setVisible(visible); - - /* - * For whatever reason, if setVisible is called, the mTmpVisible effect - * should be disabled. - */ - mTmpVisible = false; -} - -void ChatWindow::addWhisper(const std::string &nick, - const std::string &mes, const Own own) -{ - if (mes.empty() || !player_node) - return; - - std::string playerName = player_node->getName(); - std::string tempNick = nick; - - toLower(playerName); - toLower(tempNick); - - if (tempNick.compare(playerName) == 0) - return; - - WhisperTab *tab = nullptr; - const TabMap::const_iterator i = mWhispers.find(tempNick); - - if (i != mWhispers.end()) - { - tab = i->second; - } - else if (config.getBoolValue("whispertab")) - { - tab = addWhisperTab(nick); - if (tab) - saveState(); - } - - if (tab) - { - if (own == BY_PLAYER) - { - tab->chatInput(mes); - } - else if (own == BY_SERVER) - { - tab->chatLog(mes); - } - else - { - if (tab->getRemoveNames()) - { - std::string msg = mes; - const size_t idx = mes.find(":"); - if (idx != std::string::npos && idx > 0) - { - std::string nick2 = msg.substr(0, idx); - msg = msg.substr(idx + 1); - nick2 = removeColors(nick2); - nick2 = trim(nick2); - if (config.getBoolValue("removeColors")) - msg = removeColors(msg); - msg = trim(msg); - tab->chatLog(nick2, msg); - } - else - { - if (config.getBoolValue("removeColors")) - msg = removeColors(msg); - tab->chatLog(msg, BY_SERVER); - } - } - else - { - tab->chatLog(nick, mes); - } - player_node->afkRespond(tab, nick); - } - } - else if (localChatTab) - { - if (own == BY_PLAYER) - { - Net::getChatHandler()->privateMessage(nick, mes); - - // TRANSLATORS: chat message - localChatTab->chatLog(strprintf(_("Whispering to %s: %s"), - nick.c_str(), mes.c_str()), BY_PLAYER); - } - else - { - localChatTab->chatLog(std::string(nick).append( - " : ").append(mes), ACT_WHISPER, false); - if (player_node) - player_node->afkRespond(nullptr, nick); - } - } -} - -WhisperTab *ChatWindow::addWhisperTab(const std::string &nick, - const bool switchTo) -{ - if (!player_node) - return nullptr; - - std::string playerName = player_node->getName(); - std::string tempNick = nick; - - toLower(playerName); - toLower(tempNick); - - const TabMap::const_iterator i = mWhispers.find(tempNick); - WhisperTab *ret; - - if (tempNick.compare(playerName) == 0) - return nullptr; - - if (i != mWhispers.end()) - { - ret = i->second; - } - else - { - ret = new WhisperTab(this, nick); - if (gui && !player_relations.isGoodName(nick)) - ret->setLabelFont(gui->getSecureFont()); - mWhispers[tempNick] = ret; - if (config.getBoolValue("showChatHistory")) - ret->loadFromLogFile(nick); - } - - if (switchTo) - mChatTabs->setSelectedTab(ret); - - return ret; -} - -WhisperTab *ChatWindow::getWhisperTab(const std::string &nick) const -{ - if (!player_node) - return nullptr; - - std::string playerName = player_node->getName(); - std::string tempNick = nick; - - toLower(playerName); - toLower(tempNick); - - const TabMap::const_iterator i = mWhispers.find(tempNick); - WhisperTab *ret = nullptr; - - if (tempNick.compare(playerName) == 0) - return nullptr; - - if (i != mWhispers.end()) - ret = i->second; - - return ret; -} - -std::string ChatWindow::addColors(std::string &msg) -{ - // default color or chat command - if (mChatColor == 0 || msg.length() == 0 || msg.at(0) == '#' - || msg.at(0) == '/' || msg.at(0) == '@' || msg.at(0) == '!') - { - return msg; - } - - std::string newMsg(""); - const int cMap[] = {1, 4, 5, 2, 3, 6, 7, 9, 0, 8}; - - // rainbow - switch (mChatColor) - { - case 11: - msg = removeColors(msg); - for (unsigned int f = 0; f < msg.length(); f ++) - { - newMsg += "##" + toString(mRainbowColor++) + msg.at(f); - if (mRainbowColor > 9) - mRainbowColor = 0; - } - return newMsg; - case 12: - msg = removeColors(msg); - for (unsigned int f = 0; f < msg.length(); f ++) - { - newMsg += "##" + toString(cMap[mRainbowColor++]) + msg.at(f); - if (mRainbowColor > 9) - mRainbowColor = 0; - } - return newMsg; - case 13: - msg = removeColors(msg); - for (unsigned int f = 0; f < msg.length(); f ++) - { - newMsg += "##" + toString(cMap[9-mRainbowColor++]) + msg.at(f); - if (mRainbowColor > 9) - mRainbowColor = 0; - } - return newMsg; - default: - break; - } - - // simple colors - return std::string("##").append(toString(mChatColor - 1)).append(msg); -} - -void ChatWindow::autoComplete() -{ - const int caretPos = mChatInput->getCaretPosition(); - int startName = 0; - const std::string inputText = mChatInput->getText(); - bool needSecure(false); - std::string name = inputText.substr(0, caretPos); - - for (int f = caretPos - 1; f > -1; f --) - { - if (isWordSeparator(inputText[f])) - { - startName = f + 1; - name = inputText.substr(f + 1, caretPos - f); - break; - } - } - - if (caretPos - 1 + 1 == startName) - return; - - const ChatTab *const cTab = static_cast( - mChatTabs->getSelectedTab()); - StringVect nameList; - - if (cTab) - cTab->getAutoCompleteList(nameList); - std::string newName = autoComplete(nameList, name); - if (!newName.empty()) - needSecure = true; - - if (newName.empty() && actorSpriteManager) - { - actorSpriteManager->getPlayerNames(nameList, true); - newName = autoComplete(nameList, name); - if (!newName.empty()) - needSecure = true; - } - if (newName.empty()) - newName = autoCompleteHistory(name); - if (newName.empty() && spellManager) - newName = spellManager->autoComplete(name); - if (newName.empty()) - newName = autoComplete(name, &mCommands); - if (newName.empty() && actorSpriteManager) - { - actorSpriteManager->getMobNames(nameList); - newName = autoComplete(nameList, name); - } - if (newName.empty()) - newName = autoComplete(name, &mCustomWords); - if (newName.empty()) - { - whoIsOnline->getPlayerNames(nameList); - newName = autoComplete(nameList, name); - } - - if (!newName.empty()) - { - if (!startName && needSecure && (newName[0] == '/' - || newName[0] == '@' || newName[0] == '#')) - { - newName = "_" + newName; - } - mChatInput->setText(inputText.substr(0, startName).append(newName) - .append(inputText.substr(caretPos, - inputText.length() - caretPos))); - - const int len = caretPos - static_cast(name.length()) - + static_cast(newName.length()); - - if (startName > 0) - mChatInput->setCaretPosition(len + 1); - else - mChatInput->setCaretPosition(len); - } -} - -std::string ChatWindow::autoComplete(StringVect &names, - std::string partName) const -{ - StringVectCIter i = names.begin(); - const StringVectCIter i_end = names.end(); - toLower(partName); - std::string newName; - - while (i != i_end) - { - if (!i->empty()) - { - std::string name = *i; - toLower(name); - - const size_t pos = name.find(partName, 0); - if (pos == 0) - { - if (!newName.empty()) - newName = findSameSubstringI(*i, newName); - else - newName = *i; - } - } - ++i; - } - - return newName; -} - -std::string ChatWindow::autoComplete(const std::string &partName, - History *const words) const -{ - if (!words) - return ""; - - ChatCommands::const_iterator i = words->begin(); - const ChatCommands::const_iterator i_end = words->end(); - StringVect nameList; - - while (i != i_end) - { - const std::string line = *i; - if (line.find(partName, 0) == 0) - nameList.push_back(line); - ++i; - } - return autoComplete(nameList, partName); -} - -/* -void ChatWindow::moveTabLeft(ChatTab *tab) -{ - mChatTabs->moveLeft(tab); -} - -void ChatWindow::moveTabRight(ChatTab *tab) -{ - mChatTabs->moveRight(tab); -} -*/ - -std::string ChatWindow::autoCompleteHistory(const std::string &partName) const -{ - History::const_iterator i = mHistory.begin(); - const History::const_iterator i_end = mHistory.end(); - StringVect nameList; - - while (i != i_end) - { - std::string line = *i; - unsigned int f = 0; - while (f < line.length() && !isWordSeparator(line.at(f))) - f++; - - line = line.substr(0, f); - if (line != "") - nameList.push_back(line); - - ++i; - } - return autoComplete(nameList, partName); -} - -void ChatWindow::resortChatLog(std::string line, Own own, - const std::string &channel, - const bool ignoreRecord, - const bool tryRemoveColors) -{ - if (own == -1) - own = BY_SERVER; - - std::string prefix; - if (!channel.empty()) - prefix = std::string("##3").append(channel).append("##0"); - - if (tradeChatTab) - { - if (findI(line, mTradeFilter) != std::string::npos) - { - tradeChatTab->chatLog(prefix + line, own, - ignoreRecord, tryRemoveColors); - return; - } - - size_t idx2 = line.find(": "); - if (idx2 != std::string::npos) - { - const size_t idx = line.find(": \302\202"); - if (idx == idx2) - { - // ignore special message formats. - if (line.find(": \302\202\302") != std::string::npos) - return; - line = line.erase(idx + 2, 2); - tradeChatTab->chatLog(prefix + line, own, ignoreRecord, - tryRemoveColors); - return; - } - } - - const size_t idx1 = line.find("@@"); - if (idx1 != std::string::npos) - { - idx2 = line.find("|", idx1); - if (idx2 != std::string::npos) - { - const size_t idx3 = line.find("@@", idx2); - if (idx3 != std::string::npos) - { - if (line.find("http", idx1) != idx1 + 2) - { - tradeChatTab->chatLog(prefix + line, own, - ignoreRecord, tryRemoveColors); - return; - } - } - } - } - } - - if (langChatTab && !channel.empty()) - { - if (langChatTab->getChannelName() == channel) - { - langChatTab->chatLog(line, own, ignoreRecord, tryRemoveColors); - } - else if (mShowAllLang) - { - if (langChatTab) - { - langChatTab->chatLog(prefix + line, own, - ignoreRecord, tryRemoveColors); - } - else if (localChatTab) - { - localChatTab->chatLog(prefix + line, own, - ignoreRecord, tryRemoveColors); - } - } - } - else if (localChatTab && channel.empty()) - { - localChatTab->chatLog(line, own, ignoreRecord, tryRemoveColors); - } -} - -void ChatWindow::battleChatLog(const std::string &line, Own own, - const bool ignoreRecord, - const bool tryRemoveColors) -{ - if (own == -1) - own = BY_SERVER; - if (battleChatTab) - battleChatTab->chatLog(line, own, ignoreRecord, tryRemoveColors); - else if (debugChatTab) - debugChatTab->chatLog(line, own, ignoreRecord, tryRemoveColors); -} - -void ChatWindow::initTradeFilter() -{ - const std::string tradeListName = client->getServerConfigDirectory() - + "/tradefilter.txt"; - - std::ifstream tradeFile; - struct stat statbuf; - - if (!stat(tradeListName.c_str(), &statbuf) && S_ISREG(statbuf.st_mode)) - { - tradeFile.open(tradeListName.c_str(), std::ios::in); - if (tradeFile.is_open()) - { - char line[100]; - while (tradeFile.getline(line, 100)) - { - const std::string str = line; - if (!str.empty()) - mTradeFilter.push_back(str); - } - } - tradeFile.close(); - } -} - -void ChatWindow::updateOnline(std::set &onlinePlayers) const -{ - const Party *party = nullptr; - const Guild *guild = nullptr; - if (player_node) - { - party = player_node->getParty(); - guild = player_node->getGuild(); - } - FOR_EACH (TabMap::const_iterator, iter, mWhispers) - { - if (!iter->second) - return; - - WhisperTab *const tab = static_cast(iter->second); - if (!tab) - continue; - - if (onlinePlayers.find(tab->getNick()) != onlinePlayers.end()) - { - tab->setWhisperTabColors(); - } - else - { - const std::string nick = tab->getNick(); - if (actorSpriteManager) - { - const Being *const being = actorSpriteManager->findBeingByName( - nick, ActorSprite::PLAYER); - if (being) - { - tab->setWhisperTabColors(); - continue; - } - } - if (party) - { - const PartyMember *const pm = party->getMember(nick); - if (pm && pm->getOnline()) - { - tab->setWhisperTabColors(); - continue; - } - } - if (guild) - { - const GuildMember *const gm = guild->getMember(nick); - if (gm && gm->getOnline()) - { - tab->setWhisperTabColors(); - continue; - } - } - tab->setWhisperTabOfflineColors(); - } - } -} - -void ChatWindow::loadState() -{ - int num = 0; - while (num < 50) - { - const std::string nick = serverConfig.getValue( - "chatWhisper" + toString(num), ""); - - if (nick.empty()) - break; - const int flags = serverConfig.getValue( - "chatWhisperFlags" + toString(num), 1); - - ChatTab *const tab = addWhisperTab(nick); - if (tab) - { - tab->setAllowHighlight(flags & 1); - tab->setRemoveNames((flags & 2) / 2); - tab->setNoAway((flags & 4) / 4); - } - num ++; - } -} - -void ChatWindow::saveState() const -{ - int num = 0; - for (TabMap::const_iterator iter = mWhispers.begin(), - iter_end = mWhispers.end(); iter != iter_end && num < 50; ++iter) - { - if (!iter->second) - return; - - const WhisperTab *const tab = static_cast(iter->second); - - if (!tab) - continue; - - serverConfig.setValue("chatWhisper" + toString(num), - tab->getNick()); - - serverConfig.setValue("chatWhisperFlags" + toString(num), - static_cast(tab->getAllowHighlight()) - + (2 * static_cast(tab->getRemoveNames())) - + (4 * static_cast(tab->getNoAway()))); - - num ++; - } - - while (num < 50) - { - serverConfig.deleteKey("chatWhisper" + toString(num)); - serverConfig.deleteKey("chatWhisperFlags" + toString(num)); - num ++; - } -} - -std::string ChatWindow::doReplace(const std::string &msg) const -{ - std::string str = msg; - replaceSpecialChars(str); - return str; -} - -void ChatWindow::loadCustomList() -{ - std::ifstream listFile; - struct stat statbuf; - - std::string listName = client->getServerConfigDirectory() - + "/customwords.txt"; - - if (!stat(listName.c_str(), &statbuf) && S_ISREG(statbuf.st_mode)) - { - listFile.open(listName.c_str(), std::ios::in); - if (listFile.is_open()) - { - char line[101]; - while (listFile.getline(line, 100)) - { - std::string str = line; - if (!str.empty()) - mCustomWords.push_back(str); - } - } - listFile.close(); - } -} - -void ChatWindow::addToAwayLog(const std::string &line) -{ - if (!player_node || !player_node->getAway()) - return; - - if (mAwayLog.size() > 20) - mAwayLog.pop_front(); - - if (findI(line, mHighlights) != std::string::npos) - mAwayLog.push_back("##9away:" + line); -} - -void ChatWindow::displayAwayLog() const -{ - if (!localChatTab) - return; - - std::list::const_iterator i = mAwayLog.begin(); - const std::list::const_iterator i_end = mAwayLog.end(); - - while (i != i_end) - { - std::string str = *i; - localChatTab->addNewRow(str); - ++i; - } -} - -void ChatWindow::parseHighlights() -{ - mHighlights.clear(); - if (!player_node) - return; - - splitToStringVector(mHighlights, config.getStringValue( - "highlightWords"), ','); - - mHighlights.push_back(player_node->getName()); -} - -void ChatWindow::parseGlobalsFilter() -{ - mGlobalsFilter.clear(); - if (!player_node) - return; - - splitToStringVector(mGlobalsFilter, config.getStringValue( - "globalsFilter"), ','); - - mHighlights.push_back(player_node->getName()); -} - -bool ChatWindow::findHighlight(const std::string &str) -{ - return findI(str, mHighlights) != std::string::npos; -} - -void ChatWindow::copyToClipboard(const int x, const int y) const -{ - const ChatTab *const tab = getFocused(); - if (!tab) - return; - - const BrowserBox *const text = tab->mTextOutput; - if (!text) - return; - - std::string str = text->getTextAtPos(x, y); - sendBuffer(str); -} - -void ChatWindow::optionChanged(const std::string &name) -{ - if (name == "autohideChat") - mAutoHide = config.getBoolValue("autohideChat"); - else if (name == "showBattleEvents") - mShowBattleEvents = config.getBoolValue("showBattleEvents"); - else if (name == "globalsFilter") - parseGlobalsFilter(); -} - -void ChatWindow::mouseMoved(gcn::MouseEvent &event) -{ - mHaveMouse = true; - Window::mouseMoved(event); -} - -void ChatWindow::mouseEntered(gcn::MouseEvent& mouseEvent) -{ - mHaveMouse = true; - Window::mouseEntered(mouseEvent); -} - -void ChatWindow::mouseExited(gcn::MouseEvent& mouseEvent) -{ - updateVisibility(); - Window::mouseExited(mouseEvent); -} - -void ChatWindow::draw(gcn::Graphics* graphics) -{ - BLOCK_START("ChatWindow::draw") - if (!mAutoHide || mHaveMouse) - Window::draw(graphics); - BLOCK_END("ChatWindow::draw") -} - -void ChatWindow::updateVisibility() -{ - int mouseX = 0; - int mouseY = 0; - int x = 0; - int y = 0; - SDL_GetMouseState(&mouseX, &mouseY); - getAbsolutePosition(x, y); - if (mChatInput->isVisible()) - { - mHaveMouse = true; - } - else - { - mHaveMouse = mouseX >= x && mouseX <= x + getWidth() - && mouseY >= y && mouseY <= y + getHeight(); - } -} - -void ChatWindow::unHideWindow() -{ - mHaveMouse = true; -} - -#ifdef USE_PROFILER -void ChatWindow::logicChildren() -{ - BLOCK_START("ChatWindow::logicChildren") - BasicContainer::logicChildren(); - BLOCK_END("ChatWindow::logicChildren") -} -#endif - -void ChatWindow::addGlobalMessage(const std::string &line) -{ - if (debugChatTab && findI(line, mGlobalsFilter) != std::string::npos) - debugChatTab->chatLog(line, BY_OTHER); - else - localChatTab->chatLog(line, BY_GM); -} diff --git a/src/gui/chatwindow.h b/src/gui/chatwindow.h deleted file mode 100644 index 7137af08f..000000000 --- a/src/gui/chatwindow.h +++ /dev/null @@ -1,378 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_CHATWINDOW_H -#define GUI_CHATWINDOW_H - -#include "depricatedlistener.h" - -#include "configlistener.h" - -#include "utils/stringvector.h" - -#include "gui/widgets/window.h" - -#include -#include - -#include -#include -#include - -class ChatTab; -class ChatInput; -class ColorListModel; -class DropDown; -class TabbedArea; -class ItemLinkHandler; -class WhisperTab; - -const int DEFAULT_CHAT_WINDOW_SCROLL = 7; - -enum Own -{ - BY_GM = 0, - BY_PLAYER, - BY_OTHER, - BY_SERVER, - BY_CHANNEL, - ACT_WHISPER, // getting whispered at - ACT_IS, // equivalent to "/me" on IRC - BY_LOGGER, - BY_UNKNOWN = -1 -}; - -/** One item in the chat log */ -struct CHATLOG final -{ - CHATLOG() : - nick(), - text(), - own(BY_UNKNOWN) - { - } - - A_DELETE_COPY(CHATLOG) - - std::string nick; - std::string text; - Own own; -}; - -/** - * The chat window. - * - * \ingroup Interface - */ -class ChatWindow final : public Window, - public gcn::ActionListener, - public gcn::KeyListener, - public DepricatedListener, - public ConfigListener -{ - public: - /** - * Constructor. - */ - ChatWindow(); - - A_DELETE_COPY(ChatWindow) - - /** - * Destructor: used to write back values to the config file - */ - ~ChatWindow(); - - /** - * Gets the focused tab. - */ - ChatTab *getFocused() const A_WARN_UNUSED; - - /** - * Clear the given tab. - */ - void clearTab(ChatTab *const tab) const; - - /** - * Clear the current tab. - */ - void clearTab() const; - - /** - * Switch to the previous tab in order - */ - void prevTab(); - - /** - * Switch to the next tab in order - */ - void nextTab(); - - /** - * Close current chat tab - */ - void closeTab() const; - - /** - * Switch to the default tab - */ - void defaultTab(); - - /** - * Performs action. - */ - void action(const gcn::ActionEvent &event) override; - - /** - * Request focus for typing chat message. - * - * \returns true if the input was shown - * false otherwise - */ - bool requestChatFocus(); - - /** - * Checks whether ChatWindow is Focused or not. - */ - bool isInputFocused() const A_WARN_UNUSED; - - /** - * Passes the text to the current tab as input - * - * @param msg The message text which is to be sent. - */ - void chatInput(const std::string &msg) const; - - /** - * Passes the text to the local chat tab as input - * - * @param msg The message text which is to be sent. - */ - void localChatInput(const std::string &msg) const; - - /** Called when key is pressed */ - void keyPressed(gcn::KeyEvent &event) override; - - /** Set the chat input as the given text. */ - void setInputText(const std::string &text); - - /** Add the given text to the chat input. */ - void addInputText(const std::string &text, const bool space = true); - - /** Called to add item to chat */ - void addItemText(const std::string &item); - - /** Override to reset mTmpVisible */ - void setVisible(bool visible); - - /** - * Handles mouse when dragged. - */ - void mouseDragged(gcn::MouseEvent &event) override; - - /** - * Handles mouse when pressed. - */ - void mousePressed(gcn::MouseEvent &event) override; - - void processEvent(const Channels channel, - const DepricatedEvent &event) override; - - /** - * Scrolls the chat window - * - * @param amount direction and amount to scroll. Negative numbers scroll - * up, positive numbers scroll down. The absolute amount indicates the - * amount of 1/8ths of chat window real estate that should be scrolled. - */ - void scroll(const int amount) const; - - /** - * Sets the file being recorded to - * - * @param msg The file to write out to. If null, then stop recording. - */ - void setRecordingFile(const std::string &msg); - - bool getReturnTogglesChat() const A_WARN_UNUSED - { return mReturnToggles; } - - void setReturnTogglesChat(const bool toggles) - { mReturnToggles = toggles; } - - void doPresent() const; - - void addWhisper(const std::string &nick, const std::string &mes, - const Own own = BY_OTHER); - - WhisperTab *addWhisperTab(const std::string &nick, - const bool switchTo = false) A_WARN_UNUSED; - - WhisperTab *getWhisperTab(const std::string &nick) const A_WARN_UNUSED; - - void removeAllWhispers(); - - void ignoreAllWhispers(); - - void resortChatLog(std::string line, Own own, - const std::string &channel, - const bool ignoreRecord, - const bool tryRemoveColors); - - static void battleChatLog(const std::string &line, - Own own = BY_UNKNOWN, - const bool ignoreRecord = false, - const bool tryRemoveColors = true); - - void updateOnline(std::set &onlinePlayers) const; - - void loadState(); - - void saveState() const; - - void loadCustomList(); - - void loadGMCommands(); - - std::string doReplace(const std::string &msg) const A_WARN_UNUSED; - - void adjustTabSize(); - - void addToAwayLog(const std::string &line); - - void displayAwayLog() const; - - void clearAwayLog() - { mAwayLog.clear(); } - - void parseHighlights(); - - void parseGlobalsFilter(); - - bool findHighlight(const std::string &str) A_WARN_UNUSED; - - void copyToClipboard(const int x, const int y) const; - - void optionChanged(const std::string &name) override; - - void mouseEntered(gcn::MouseEvent& mouseEvent) override; - - void mouseMoved(gcn::MouseEvent &event) override; - - void mouseExited(gcn::MouseEvent& mouseEvent A_UNUSED) override; - - void draw(gcn::Graphics* graphics) override; - - void updateVisibility(); - - void unHideWindow(); - - void widgetResized(const gcn::Event &event) override; - - void addGlobalMessage(const std::string &line); - -#ifdef USE_PROFILER - void logicChildren(); -#endif - - protected: - friend class ChatTab; - friend class WhisperTab; - friend class PopupMenu; - - typedef std::list History; - - /** Remove the given tab from the window */ - void removeTab(ChatTab *const tab); - - /** Add the tab to the window */ - void addTab(ChatTab *const tab); - - void removeWhisper(const std::string &nick); - - void autoComplete(); - - std::string addColors(std::string &msg); - - std::string autoCompleteHistory(const std::string &partName) const; - - std::string autoComplete(const std::string &partName, - History *const words) const; - - std::string autoComplete(StringVect &names, - std::string partName) const; - - /** Used for showing item popup on clicking links **/ - ItemLinkHandler *mItemLinkHandler; - - /** Tabbed area for holding each channel. */ - TabbedArea *mChatTabs; - - /** Input box for typing chat messages. */ - ChatInput *mChatInput; - - void initTradeFilter(); - - int mRainbowColor; - - private: - void fillCommands(); - - void loadCommandsFile(const std::string &name); - - - typedef std::map TabMap; - /** Manage whisper tabs */ - TabMap mWhispers; - - typedef History::iterator HistoryIterator; - History mHistory; /**< Command history. */ - HistoryIterator mCurHist; /**< History iterator. */ - - typedef std::list ChatCommands; - typedef ChatCommands::iterator ChatCommandsIterator; - History mCommands; /**< Command list. */ - History mCustomWords; - - bool mReturnToggles; // Marks whether toggles the chat log - // or not - - StringVect mTradeFilter; - - ColorListModel *mColorListModel; - DropDown *mColorPicker; - int mChatColor; - unsigned int mChatHistoryIndex; - std::list mAwayLog; - StringVect mHighlights; - StringVect mGlobalsFilter; - bool mGMLoaded; - bool mHaveMouse; - bool mAutoHide; - bool mShowBattleEvents; - bool mShowAllLang; - bool mTmpVisible; -}; - -extern ChatWindow *chatWindow; - -#endif // GUI_CHATWINDOW_H diff --git a/src/gui/confirmdialog.cpp b/src/gui/confirmdialog.cpp deleted file mode 100644 index 08ef09d64..000000000 --- a/src/gui/confirmdialog.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/confirmdialog.h" - -#include "soundmanager.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/textbox.h" - -#include "utils/gettext.h" - -#include - -#include "debug.h" - -ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg, - const std::string &soundEvent, const bool ignore, - const bool modal, Window *const parent): - Window(title, modal, parent, "confirm.xml"), - gcn::ActionListener(), - mTextBox(new TextBox(this)) -{ - mTextBox->setEditable(false); - mTextBox->setOpaque(false); - mTextBox->setTextWrapped(msg, 260); - - // TRANSLATORS: confirm dialog button - Button *const yesButton = new Button(this, _("Yes"), "yes", this); - // TRANSLATORS: confirm dialog button - Button *const noButton = new Button(this, _("No"), "no", this); - Button *const ignoreButton = ignore ? new Button( - // TRANSLATORS: confirm dialog button - this, _("Ignore"), "ignore", this) : nullptr; - - const int numRows = mTextBox->getNumberOfRows(); - int inWidth = yesButton->getWidth() + noButton->getWidth() + - (2 * mPadding); - - if (ignoreButton) - inWidth += ignoreButton->getWidth(); - - const int fontHeight = getFont()->getHeight(); - const int height = numRows * fontHeight; - int width = getFont()->getWidth(title); - - if (width < mTextBox->getMinWidth()) - width = mTextBox->getMinWidth(); - if (width < inWidth) - width = inWidth; - - setContentSize(mTextBox->getMinWidth() + fontHeight, height + fontHeight + - noButton->getHeight()); - mTextBox->setPosition(mPadding, mPadding); - - // 8 is the padding that GUIChan adds to button widgets - // (top and bottom combined) - const int buttonPadding = getOption("buttonPadding", 8); - yesButton->setPosition((width - inWidth) / 2, height + buttonPadding); - noButton->setPosition(yesButton->getX() + yesButton->getWidth() - + (2 * mPadding), height + buttonPadding); - if (ignoreButton) - { - ignoreButton->setPosition(noButton->getX() + noButton->getWidth() - + (2 * mPadding), height + buttonPadding); - } - - add(mTextBox); - add(yesButton); - add(noButton); - - if (ignore && ignoreButton) - add(ignoreButton); - - if (getParent()) - { - center(); - getParent()->moveToTop(this); - } - setVisible(true); - yesButton->requestFocus(); - soundManager.playGuiSound(soundEvent); -} - -void ConfirmDialog::action(const gcn::ActionEvent &event) -{ - setActionEventId(event.getId()); - distributeActionEvent(); - scheduleDelete(); -} diff --git a/src/gui/confirmdialog.h b/src/gui/confirmdialog.h deleted file mode 100644 index 76e3c2d18..000000000 --- a/src/gui/confirmdialog.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_CONFIRMDIALOG_H -#define GUI_CONFIRMDIALOG_H - -#include "localconsts.h" - -#include "soundconsts.h" - -#include "gui/widgets/window.h" - -#include - -class TextBox; - -/** - * An option dialog. - * - * \ingroup GUI - */ -class ConfirmDialog : public Window, public gcn::ActionListener -{ - public: - /** - * Constructor. - * - * @see Window::Window - */ - ConfirmDialog(const std::string &title, const std::string &msg, - const std::string &soundEvent = SOUND_REQUEST, - const bool ignore = false, const bool modal = false, - Window *const parent = nullptr); - - A_DELETE_COPY(ConfirmDialog) - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - private: - TextBox *mTextBox; -}; - -#endif // GUI_CONFIRMDIALOG_H diff --git a/src/gui/connectiondialog.cpp b/src/gui/connectiondialog.cpp deleted file mode 100644 index 97894492f..000000000 --- a/src/gui/connectiondialog.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/connectiondialog.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/label.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/progressindicator.h" - -#include "utils/gettext.h" - -#include "debug.h" - -ConnectionDialog::ConnectionDialog(const std::string &text, - const State cancelState): - Window(""), - gcn::ActionListener(), - mCancelState(cancelState) -{ - setTitleBarHeight(0); - setMovable(false); - setMinWidth(0); - - ProgressIndicator *const progressIndicator = new ProgressIndicator; - Label *const label = new Label(this, text); - Button *const cancelButton = new Button( - // TRANSLATORS: connection dialog button - this, _("Cancel"), "cancelButton", this); - - place(0, 0, progressIndicator); - place(0, 1, label); - place(0, 2, cancelButton).setHAlign(LayoutCell::CENTER); - reflowLayout(); - - center(); - setVisible(true); -} - -void ConnectionDialog::action(const gcn::ActionEvent &) -{ - logger->log1("Cancel pressed"); - client->setState(mCancelState); -} - -void ConnectionDialog::draw(gcn::Graphics *graphics) -{ - BLOCK_START("ConnectionDialog::draw") - // Don't draw the window background, only draw the children - drawChildren(graphics); - BLOCK_END("ConnectionDialog::draw") -} diff --git a/src/gui/connectiondialog.h b/src/gui/connectiondialog.h deleted file mode 100644 index 21f29712c..000000000 --- a/src/gui/connectiondialog.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_CONNECTIONDIALOG_H -#define GUI_CONNECTIONDIALOG_H - -#include "client.h" - -#include "gui/widgets/window.h" - -#include - -/** - * The connection dialog. - * - * \ingroup Interface - */ -class ConnectionDialog final : public Window, private gcn::ActionListener -{ - public: - /** - * Constructor. - * - * @param text The text to display - * @param cancelState The state to enter when Cancel is pressed - * - * @see Window::Window - */ - ConnectionDialog(const std::string &text, const State cancelState); - - A_DELETE_COPY(ConnectionDialog) - - /** - * Called when the user presses Cancel. Restores the global state to - * the previous one. - */ - void action(const gcn::ActionEvent &) override; - - void draw(gcn::Graphics *graphics) override; - - private: - State mCancelState; -}; - -#endif // GUI_CONNECTIONDIALOG_H diff --git a/src/gui/debugwindow.cpp b/src/gui/debugwindow.cpp deleted file mode 100644 index 39f07dffb..000000000 --- a/src/gui/debugwindow.cpp +++ /dev/null @@ -1,536 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/debugwindow.h" - -#include "client.h" -#include "game.h" -#include "main.h" - -#include "being/localplayer.h" - -#include "particle/particle.h" - -#include "gui/setup.h" -#include "gui/viewport.h" - -#include "gui/widgets/label.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/layouthelper.h" - -#include "resources/imagehelper.h" - -#include "net/packetcounters.h" - -#include "utils/gettext.h" - -#include "debug.h" - -DebugWindow::DebugWindow() : - // TRANSLATORS: debug window name - Window(_("Debug"), false, nullptr, "debug.xml"), - mTabs(new TabbedArea(this)), - mMapWidget(new MapDebugTab(this)), - mTargetWidget(new TargetDebugTab(this)), - mNetWidget(new NetDebugTab(this)) -{ - setWindowName("Debug"); - if (setupWindow) - setupWindow->registerWindowForReset(this); - - setResizable(true); - setCloseButton(true); - setSaveVisible(true); - setStickyButtonLock(true); - - setDefaultSize(400, 300, ImageRect::CENTER); - - // TRANSLATORS: debug window tab - mTabs->addTab(std::string(_("Map")), mMapWidget); - // TRANSLATORS: debug window tab - mTabs->addTab(std::string(_("Target")), mTargetWidget); - // TRANSLATORS: debug window tab - mTabs->addTab(std::string(_("Net")), mNetWidget); - - mTabs->setDimension(gcn::Rectangle(0, 0, 600, 300)); - add(mTabs); - - const int w = mDimension.width; - const int h = mDimension.height; - mMapWidget->resize(w, h); - mTargetWidget->resize(w, h); - mNetWidget->resize(w, h); - loadWindowState(); - enableVisibleSound(true); -} - -DebugWindow::~DebugWindow() -{ - delete mMapWidget; - mMapWidget = nullptr; - delete mTargetWidget; - mTargetWidget = nullptr; - delete mNetWidget; - mNetWidget = nullptr; -} - -void DebugWindow::slowLogic() -{ - BLOCK_START("DebugWindow::slowLogic") - if (!isWindowVisible() || !mTabs) - { - BLOCK_END("DebugWindow::slowLogic") - return; - } - - switch (mTabs->getSelectedTabIndex()) - { - default: - case 0: - mMapWidget->logic(); - break; - case 1: - mTargetWidget->logic(); - break; - case 2: - mNetWidget->logic(); - break; - } - - if (player_node) - player_node->tryPingRequest(); - BLOCK_END("DebugWindow::slowLogic") -} - -void DebugWindow::draw(gcn::Graphics *g) -{ - BLOCK_START("DebugWindow::draw") - Window::draw(g); - - if (player_node) - { - const Being *const target = player_node->getTarget(); - if (target) - { - Graphics *const g2 = static_cast(g); - target->draw(g2, -target->getPixelX() + 16 + mDimension.width / 2, - -target->getPixelY() + 32 + mDimension.height / 2); - } - } - BLOCK_END("DebugWindow::draw") -} - -void DebugWindow::widgetResized(const gcn::Event &event) -{ - Window::widgetResized(event); - - mTabs->setDimension(gcn::Rectangle(0, 0, - mDimension.width, mDimension.height)); -} - -#ifdef USE_PROFILER -void DebugWindow::logicChildren() -{ - BLOCK_START("DebugWindow::logicChildren") - BasicContainer::logicChildren(); - BLOCK_END("DebugWindow::logicChildren") -} -#endif - -MapDebugTab::MapDebugTab(const Widget2 *const widget) : - DebugTab(widget), - // TRANSLATORS: debug window label - mMusicFileLabel(new Label(this, strprintf(_("Music:")))), - // TRANSLATORS: debug window label - mMapLabel(new Label(this, strprintf(_("Map:")))), - // TRANSLATORS: debug window label - mMinimapLabel(new Label(this, strprintf(_("Minimap:")))), - mTileMouseLabel(new Label(this, strprintf("%s (%d, %d)", - // TRANSLATORS: debug window label - _("Cursor:"), 0, 0))), - mParticleCountLabel(new Label(this, strprintf("%s %d", - // TRANSLATORS: debug window label - _("Particle count:"), 88888))), - mMapActorCountLabel(new Label(this, strprintf("%s %d", - // TRANSLATORS: debug window label - _("Map actors count:"), 88888))), - // TRANSLATORS: debug window label - mXYLabel(new Label(this, strprintf("%s (?,?)", _("Player Position:")))), - mTexturesLabel(nullptr), - mUpdateTime(0), -#ifdef DEBUG_DRAW_CALLS - mDrawCallsLabel(new Label(this, strprintf("%s %s", - // TRANSLATORS: debug window label - _("Draw calls:"), "?"))), -#endif -#ifdef DEBUG_BIND_TEXTURE - mBindsLabel(new Label(this, strprintf("%s %s", - // TRANSLATORS: debug window label - _("Texture binds:"), "?"))), -#endif - // TRANSLATORS: debug window label, frames per second - mFPSLabel(new Label(this, strprintf(_("%d FPS"), 0))), - // TRANSLATORS: debug window label, logic per second - mLPSLabel(new Label(this, strprintf(_("%d LPS"), 0))), - mFPSText() -{ - LayoutHelper h(this); - ContainerPlacer place = h.getPlacer(0, 0); - -#ifdef USE_OPENGL - switch (imageHelper->useOpenGL()) - { - case RENDER_SOFTWARE: - // TRANSLATORS: debug window label - mFPSText = _("%d FPS (Software)"); - break; - case RENDER_NORMAL_OPENGL: - case RENDER_NULL: - case RENDER_LAST: - default: - // TRANSLATORS: debug window label - mFPSText = _("%d FPS (normal OpenGL)"); - break; - case RENDER_SAFE_OPENGL: - // TRANSLATORS: debug window label - mFPSText = _("%d FPS (safe OpenGL)"); - break; - case RENDER_GLES_OPENGL: - // TRANSLATORS: debug window label - mFPSText = _("%d FPS (mobile OpenGL)"); - break; - case RENDER_SDL2_DEFAULT: - // TRANSLATORS: debug window label - mFPSText = _("%d FPS (SDL2 default)"); - break; - }; -#else - // TRANSLATORS: debug window label - mFPSText = _("%d FPS (Software)"); -#endif - - place(0, 0, mFPSLabel, 2); - place(0, 1, mLPSLabel, 2); - place(0, 2, mMusicFileLabel, 2); - place(0, 3, mMapLabel, 2); - place(0, 4, mMinimapLabel, 2); - place(0, 5, mXYLabel, 2); - place(0, 6, mTileMouseLabel, 2); - place(0, 7, mParticleCountLabel, 2); - place(0, 8, mMapActorCountLabel, 2); -#ifdef USE_OPENGL -#if defined (DEBUG_OPENGL_LEAKS) || defined(DEBUG_DRAW_CALLS) \ - || defined(DEBUG_BIND_TEXTURE) - int n = 9; -#endif -#ifdef DEBUG_OPENGL_LEAKS - mTexturesLabel = new Label(this, strprintf("%s %s", - // TRANSLATORS: debug window label - _("Textures count:"), "?")); - place(0, n, mTexturesLabel, 2); - n ++; -#endif -#ifdef DEBUG_DRAW_CALLS - place(0, n, mDrawCallsLabel, 2); - n ++; -#endif -#ifdef DEBUG_BIND_TEXTURE - place(0, n, mBindsLabel, 2); -#endif -#endif - place.getCell().matchColWidth(0, 0); - place = h.getPlacer(0, 1); - setDimension(gcn::Rectangle(0, 0, 600, 300)); -} - -void MapDebugTab::logic() -{ - if (player_node) - { - // TRANSLATORS: debug window label - mXYLabel->setCaption(strprintf("%s (%d, %d)", _("Player Position:"), - player_node->getTileX(), player_node->getTileY())); - } - else - { - // TRANSLATORS: debug window label - mXYLabel->setCaption(strprintf("%s (?, ?)", _("Player Position:"))); - } - - const Map *const map = Game::instance()->getCurrentMap(); - if (map && viewport) - { - // Get the current mouse position - const int mouseTileX = (viewport->getMouseX() + viewport->getCameraX()) - / map->getTileWidth(); - const int mouseTileY = (viewport->getMouseY() + viewport->getCameraY()) - / map->getTileHeight(); - mTileMouseLabel->setCaption(strprintf("%s (%d, %d)", - // TRANSLATORS: debug window label - _("Cursor:"), mouseTileX, mouseTileY)); - - // TRANSLATORS: debug window label - mMusicFileLabel->setCaption(strprintf("%s %s", _("Music:"), - map->getProperty("music").c_str())); - // TRANSLATORS: debug window label - mMinimapLabel->setCaption(strprintf("%s %s", _("Minimap:"), - map->getProperty("minimap").c_str())); - // TRANSLATORS: debug window label - mMapLabel->setCaption(strprintf("%s %s", _("Map:"), - map->getProperty("_realfilename").c_str())); - - - if (mUpdateTime != cur_time) - { - mUpdateTime = cur_time; - // TRANSLATORS: debug window label - mParticleCountLabel->setCaption(strprintf(_("Particle count: %d"), - Particle::particleCount)); - - mMapActorCountLabel->setCaption( - // TRANSLATORS: debug window label - strprintf("%s %d", _("Map actors count:"), - map->getActorsCount())); -#ifdef USE_OPENGL -#ifdef DEBUG_OPENGL_LEAKS - mTexturesLabel->setCaption(strprintf("%s %d", - // TRANSLATORS: debug window label - _("Textures count:"), textures_count)); -#endif -#ifdef DEBUG_DRAW_CALLS - if (mainGraphics) - { - mDrawCallsLabel->setCaption(strprintf("%s %d", - // TRANSLATORS: debug window label - _("Draw calls:"), mainGraphics->getDrawCalls())); - } -#endif -#ifdef DEBUG_BIND_TEXTURE - if (mainGraphics) - { - mBindsLabel->setCaption(strprintf("%s %d", - // TRANSLATORS: debug window label - _("Texture binds:"), mainGraphics->getBinds())); - } -#endif -#endif - } - } - else - { - // TRANSLATORS: debug window label - mTileMouseLabel->setCaption(strprintf("%s (?, ?)", _("Cursor:"))); - // TRANSLATORS: debug window label - mMusicFileLabel->setCaption(strprintf("%s ?", _("Music:"))); - // TRANSLATORS: debug window label - mMinimapLabel->setCaption(strprintf("%s ?", _("Minimap:"))); - // TRANSLATORS: debug window label - mMapLabel->setCaption(strprintf("%s ?", _("Map:"))); - - mMapActorCountLabel->setCaption( - // TRANSLATORS: debug window label - strprintf("%s ?", _("Map actors count:"))); - } - - mMapActorCountLabel->adjustSize(); - mParticleCountLabel->adjustSize(); - - mFPSLabel->setCaption(strprintf(mFPSText.c_str(), fps)); - // TRANSLATORS: debug window label, logic per second - mLPSLabel->setCaption(strprintf(_("%d LPS"), lps)); -} - -TargetDebugTab::TargetDebugTab(const Widget2 *const widget) : - DebugTab(widget), - // TRANSLATORS: debug window label - mTargetLabel(new Label(this, strprintf("%s ?", _("Target:")))), - // TRANSLATORS: debug window label - mTargetIdLabel(new Label(this, strprintf("%s ? ", _("Target Id:")))), - mTargetTypeLabel(new Label(this, strprintf( - // TRANSLATORS: debug window label - "%s ? ", _("Target type:")))), - // TRANSLATORS: debug window label - mTargetLevelLabel(new Label(this, strprintf("%s ?", _("Target level:")))), - // TRANSLATORS: debug window label - mTargetRaceLabel(new Label(this, strprintf("%s ?", _("Target race:")))), - // TRANSLATORS: debug window label - mTargetPartyLabel(new Label(this, strprintf("%s ?", _("Target party:")))), - // TRANSLATORS: debug window label - mTargetGuildLabel(new Label(this, strprintf("%s ?", _("Target guild:")))), - // TRANSLATORS: debug window label - mAttackDelayLabel(new Label(this, strprintf("%s ?", _("Attack delay:")))), - // TRANSLATORS: debug window label - mMinHitLabel(new Label(this, strprintf("%s ?", _("Minimal hit:")))), - // TRANSLATORS: debug window label - mMaxHitLabel(new Label(this, strprintf("%s ?", _("Maximum hit:")))), - // TRANSLATORS: debug window label - mCriticalHitLabel(new Label(this, strprintf("%s ?", _("Critical hit:")))) -{ - LayoutHelper h(this); - ContainerPlacer place = h.getPlacer(0, 0); - - place(0, 0, mTargetLabel, 2); - place(0, 1, mTargetIdLabel, 2); - place(0, 2, mTargetTypeLabel, 2); - place(0, 3, mTargetLevelLabel, 2); - place(0, 4, mTargetRaceLabel, 2); - place(0, 5, mAttackDelayLabel, 2); - place(0, 6, mTargetPartyLabel, 2); - place(0, 7, mTargetGuildLabel, 2); - place(0, 8, mMinHitLabel, 2); - place(0, 9, mMaxHitLabel, 2); - place(0, 10, mCriticalHitLabel, 2); - - place.getCell().matchColWidth(0, 0); - place = h.getPlacer(0, 1); - setDimension(gcn::Rectangle(0, 0, 600, 300)); -} - -void TargetDebugTab::logic() -{ - if (player_node && player_node->getTarget()) - { - const Being *const target = player_node->getTarget(); - - // TRANSLATORS: debug window label - mTargetLabel->setCaption(strprintf("%s %s (%d, %d)", _("Target:"), - target->getName().c_str(), target->getTileX(), - target->getTileY())); - - mTargetIdLabel->setCaption(strprintf("%s %d", - // TRANSLATORS: debug window label - _("Target Id:"), target->getId())); - mTargetTypeLabel->setCaption(strprintf("%s %d", - // TRANSLATORS: debug window label - _("Target type:"), target->getSubType())); - if (target->getLevel()) - { - mTargetLevelLabel->setCaption(strprintf("%s %d", - // TRANSLATORS: debug window label - _("Target Level:"), target->getLevel())); - } - else - { - mTargetLevelLabel->setCaption(strprintf("%s ?", - // TRANSLATORS: debug window label - _("Target Level:"))); - } - - mTargetRaceLabel->setCaption(strprintf("%s %s", - // TRANSLATORS: debug window label - _("Target race:"), target->getRaceName().c_str())); - - // TRANSLATORS: debug window label - mTargetPartyLabel->setCaption(strprintf("%s %s", _("Target Party:"), - target->getPartyName().c_str())); - - // TRANSLATORS: debug window label - mTargetGuildLabel->setCaption(strprintf("%s %s", _("Target Guild:"), - target->getGuildName().c_str())); - - mMinHitLabel->setCaption(strprintf("%s %d", - // TRANSLATORS: debug window label - _("Minimal hit:"), target->getMinHit())); - mMaxHitLabel->setCaption(strprintf("%s %d", - // TRANSLATORS: debug window label - _("Maximum hit:"), target->getMaxHit())); - mCriticalHitLabel->setCaption(strprintf("%s %d", - // TRANSLATORS: debug window label - _("Critical hit:"), target->getCriticalHit())); - - const int delay = target->getAttackDelay(); - if (delay) - { - mAttackDelayLabel->setCaption(strprintf("%s %d", - // TRANSLATORS: debug window label - _("Attack delay:"), delay)); - } - else - { - mAttackDelayLabel->setCaption(strprintf( - // TRANSLATORS: debug window label - "%s ?", _("Attack delay:"))); - } - } - else - { - // TRANSLATORS: debug window label - mTargetLabel->setCaption(strprintf("%s ?", _("Target:"))); - // TRANSLATORS: debug window label - mTargetIdLabel->setCaption(strprintf("%s ?", _("Target Id:"))); - // TRANSLATORS: debug window label - mTargetTypeLabel->setCaption(strprintf("%s ?", _("Target type:"))); - // TRANSLATORS: debug window label - mTargetLevelLabel->setCaption(strprintf("%s ?", _("Target Level:"))); - // TRANSLATORS: debug window label - mTargetPartyLabel->setCaption(strprintf("%s ?", _("Target Party:"))); - // TRANSLATORS: debug window label - mTargetGuildLabel->setCaption(strprintf("%s ?", _("Target Guild:"))); - // TRANSLATORS: debug window label - mAttackDelayLabel->setCaption(strprintf("%s ?", _("Attack delay:"))); - // TRANSLATORS: debug window label - mMinHitLabel->setCaption(strprintf("%s ?", _("Minimal hit:"))); - // TRANSLATORS: debug window label - mMaxHitLabel->setCaption(strprintf("%s ?", _("Maximum hit:"))); - // TRANSLATORS: debug window label - mCriticalHitLabel->setCaption(strprintf("%s ?", _("Critical hit:"))); - } - - mTargetLabel->adjustSize(); - mTargetIdLabel->adjustSize(); - mTargetTypeLabel->adjustSize(); - mTargetLevelLabel->adjustSize(); - mTargetPartyLabel->adjustSize(); - mTargetGuildLabel->adjustSize(); - mAttackDelayLabel->adjustSize(); -} - -NetDebugTab::NetDebugTab(const Widget2 *const widget) : - DebugTab(widget), - mPingLabel(new Label(this, " ")), - mInPackets1Label(new Label(this, " ")), - mOutPackets1Label(new Label(this, " ")) -{ - LayoutHelper h(this); - ContainerPlacer place = h.getPlacer(0, 0); - - place(0, 0, mPingLabel, 2); - place(0, 1, mInPackets1Label, 2); - place(0, 2, mOutPackets1Label, 2); - - place.getCell().matchColWidth(0, 0); - place = h.getPlacer(0, 1); - setDimension(gcn::Rectangle(0, 0, 600, 300)); -} - -void NetDebugTab::logic() -{ - // TRANSLATORS: debug window label - mPingLabel->setCaption(strprintf(_("Ping: %s ms"), - player_node->getPingTime().c_str())); - // TRANSLATORS: debug window label - mInPackets1Label->setCaption(strprintf(_("In: %d bytes/s"), - PacketCounters::getInBytes())); - // TRANSLATORS: debug window label - mOutPackets1Label->setCaption(strprintf(_("Out: %d bytes/s"), - PacketCounters::getOutBytes())); -} diff --git a/src/gui/debugwindow.h b/src/gui/debugwindow.h deleted file mode 100644 index ef67df432..000000000 --- a/src/gui/debugwindow.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_DEBUGWINDOW_H -#define GUI_DEBUGWINDOW_H - -#include "gui/widgets/container.h" -#include "gui/widgets/window.h" - -class Label; -class TabbedArea; - -class DebugTab : public Container -{ - friend class DebugWindow; - - public: - A_DELETE_COPY(DebugTab) - - void logic() override = 0; - - void resize(const int x, const int y) - { setDimension(gcn::Rectangle(0, 0, x, y)); } - - protected: - explicit DebugTab(const Widget2 *const widget) : - Container(widget) - { } -}; - -class MapDebugTab final : public DebugTab -{ - friend class DebugWindow; - - public: - explicit MapDebugTab(const Widget2 *const widget); - - A_DELETE_COPY(MapDebugTab) - - void logic() override; - - private: - Label *mMusicFileLabel; - Label *mMapLabel; - Label *mMinimapLabel; - Label *mTileMouseLabel; - Label *mParticleCountLabel; - Label *mMapActorCountLabel; - Label *mXYLabel; - Label *mTexturesLabel; - int mUpdateTime; -#ifdef DEBUG_DRAW_CALLS - Label *mDrawCallsLabel; -#endif -#ifdef DEBUG_BIND_TEXTURE - Label *mBindsLabel; -#endif - Label *mFPSLabel; - Label *mLPSLabel; - std::string mFPSText; -}; - -class TargetDebugTab final : public DebugTab -{ - friend class DebugWindow; - - public: - explicit TargetDebugTab(const Widget2 *const widget); - - A_DELETE_COPY(TargetDebugTab) - - void logic() override; - - private: - Label *mTargetLabel; - Label *mTargetIdLabel; - Label *mTargetTypeLabel; - Label *mTargetLevelLabel; - Label *mTargetRaceLabel; - Label *mTargetPartyLabel; - Label *mTargetGuildLabel; - Label *mAttackDelayLabel; - Label *mMinHitLabel; - Label *mMaxHitLabel; - Label *mCriticalHitLabel; -}; - -class NetDebugTab final : public DebugTab -{ - friend class DebugWindow; - - public: - explicit NetDebugTab(const Widget2 *const widget); - - A_DELETE_COPY(NetDebugTab) - - void logic() override; - - private: - Label *mPingLabel; - Label *mInPackets1Label; - Label *mOutPackets1Label; -}; - -/** - * The debug window. - * - * \ingroup Interface - */ -class DebugWindow final : public Window -{ - public: - /** - * Constructor. - */ - DebugWindow(); - - A_DELETE_COPY(DebugWindow) - - ~DebugWindow(); - - /** - * Logic (updates components' size and infos) - */ - void slowLogic(); - - void draw(gcn::Graphics *g) override; - - void setPing(int pingTime); - - void widgetResized(const gcn::Event &event) override; - -#ifdef USE_PROFILER - void logicChildren(); -#endif - - private: - TabbedArea *mTabs; - MapDebugTab *mMapWidget; - TargetDebugTab *mTargetWidget; - NetDebugTab *mNetWidget; -}; - -extern DebugWindow *debugWindow; - -#endif // GUI_DEBUGWINDOW_H diff --git a/src/gui/didyouknowwindow.cpp b/src/gui/didyouknowwindow.cpp deleted file mode 100644 index 68ecfdfd3..000000000 --- a/src/gui/didyouknowwindow.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/didyouknowwindow.h" - -#include "configuration.h" - -#include "gui/gui.h" -#include "gui/sdlfont.h" -#include "gui/setup.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/browserbox.h" -#include "gui/widgets/checkbox.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/scrollarea.h" - -#include "utils/gettext.h" -#include "utils/process.h" - -#include "utils/translation/podict.h" -#include "utils/translation/translationmanager.h" - -#include "debug.h" - -static const int minTip = 1; -static const int maxTip = 18; - -DidYouKnowWindow::DidYouKnowWindow() : - // TRANSLATORS: did you know window name - Window(_("Did You Know?"), false, nullptr, "didyouknow.xml"), - gcn::ActionListener(), - mBrowserBox(new BrowserBox(this)), - mScrollArea(new ScrollArea(mBrowserBox, - true, "didyouknow_background.xml")), - // TRANSLATORS: did you know window button - mButtonPrev(new Button(this, _("< Previous"), "prev", this)), - // TRANSLATORS: did you know window button - mButtonNext(new Button(this, _("Next >"), "next", this)), - // TRANSLATORS: did you know window checkbox - mOpenAgainCheckBox(new CheckBox(this, _("Auto open this window"), - config.getBoolValue("showDidYouKnow"), this, "openagain")) -{ - setMinWidth(300); - setMinHeight(220); - setContentSize(455, 350); - setWindowName("DidYouKnow"); - setCloseButton(true); - setResizable(true); - setStickyButtonLock(true); - - if (setupWindow) - setupWindow->registerWindowForReset(this); - setDefaultSize(500, 400, ImageRect::CENTER); - - mBrowserBox->setOpaque(false); - // TRANSLATORS: did you know window button - Button *const okButton = new Button(this, _("Close"), "close", this); - - mBrowserBox->setLinkHandler(this); - mBrowserBox->setFont(gui->getHelpFont()); - mBrowserBox->setProcessVersion(true); - mBrowserBox->setEnableImages(true); - mBrowserBox->setEnableKeys(true); - mBrowserBox->setEnableTabs(true); - - place(0, 0, mScrollArea, 5, 3).setPadding(3); - place(0, 3, mOpenAgainCheckBox, 5); - place(1, 4, mButtonPrev, 1); - place(2, 4, mButtonNext, 1); - place(4, 4, okButton); - - Layout &layout = getLayout(); - layout.setRowHeight(0, Layout::AUTO_SET); - - loadWindowState(); - enableVisibleSound(true); - widgetResized(gcn::Event(nullptr)); -} - -void DidYouKnowWindow::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "close") - { - setVisible(false); - } - else - { - const unsigned num = config.getIntValue("currentTip"); - if (eventId == "prev") - { - loadData(num - 1); - } - else if (eventId == "next") - { - loadData(num + 1); - } - else if (eventId == "openagain") - { - config.setValue("showDidYouKnow", - mOpenAgainCheckBox->isSelected()); - } - } -} - -void DidYouKnowWindow::handleLink(const std::string &link, - gcn::MouseEvent *event A_UNUSED) -{ - if (strStartWith(link, "http://") || strStartWith(link, "https://")) - openBrowser(link); -} - -void DidYouKnowWindow::loadData(int num) -{ - mBrowserBox->clearRows(); - if (!num) - { - const int curTip = config.getIntValue("currentTip"); - if (curTip == 1) - num = maxTip; - else - num = curTip + 1; - } - - if (num < minTip || num > maxTip) - num = minTip; - - config.setValue("currentTip", num); - - loadFile(num); - - mScrollArea->setVerticalScrollAmount(0); -} - -void DidYouKnowWindow::loadFile(const int num) -{ - const std::string file = strprintf("tips/%d", num); - std::string helpPath = branding.getStringValue("helpPath"); - if (helpPath.empty()) - helpPath = paths.getStringValue("help"); - - StringVect lines; - TranslationManager::translateFile(helpPath.append(file).append(".txt"), - translator, lines); - - for (size_t i = 0, sz = lines.size(); i < sz; ++i) - mBrowserBox->addRow(lines[i]); -} - -void DidYouKnowWindow::setVisible(bool visible) -{ - Window::setVisible(visible); - - if (visible || isWindowVisible()) - loadData(); -} diff --git a/src/gui/didyouknowwindow.h b/src/gui/didyouknowwindow.h deleted file mode 100644 index 49cb07a8b..000000000 --- a/src/gui/didyouknowwindow.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_DIDYOUKNOWWINDOW_H -#define GUI_DIDYOUKNOWWINDOW_H - -#include "gui/widgets/linkhandler.h" -#include "gui/widgets/window.h" - -#include - -class Button; -class BrowserBox; -class CheckBox; -class ScrollArea; - -/** - * The help dialog. - */ -class DidYouKnowWindow final : public Window, - public LinkHandler, - public gcn::ActionListener -{ - public: - /** - * Constructor. - */ - DidYouKnowWindow(); - - A_DELETE_COPY(DidYouKnowWindow) - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - /** - * Handles link action. - */ - void handleLink(const std::string &link, - gcn::MouseEvent *event) override; - - void loadData(int num = 0); - - void setVisible(bool visible); - - private: - void loadFile(const int num); - - BrowserBox *mBrowserBox; - ScrollArea *mScrollArea; - Button *mButtonPrev; - Button *mButtonNext; - CheckBox *mOpenAgainCheckBox; -}; - -extern DidYouKnowWindow *didYouKnowWindow; - -#endif // GUI_DIDYOUKNOWWINDOW_H diff --git a/src/gui/editdialog.cpp b/src/gui/editdialog.cpp deleted file mode 100644 index fa6b1e123..000000000 --- a/src/gui/editdialog.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 Andrei Karas - * Copyright (C) 2011-2013 The ManaPlus developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/editdialog.h" - -#include "gui/widgets/button.h" - -#include "utils/gettext.h" - -#include - -#include "debug.h" - -EditDialog::EditDialog(const std::string &title, const std::string &msg, - const std::string &eventOk, const int width, - Window *const parent, const bool modal): - Window(title, modal, parent, "edit.xml"), - gcn::ActionListener(), - mEventOk(eventOk), - mTextField(new TextField(this)) -{ - mTextField->setText(msg); - // TRANSLATORS: edit dialog label - Button *const okButton = new Button(this, _("OK"), mEventOk, this); - - const int numRows = 1; - const int fontHeight = getFont()->getHeight(); - const int height = numRows * fontHeight; - - setContentSize(width, height + fontHeight + okButton->getHeight()); - mTextField->setPosition(getPadding(), getPadding()); - mTextField->setWidth(width - (2 * getPadding())); - - okButton->setPosition((width - okButton->getWidth()) / 2, - height + getOption("buttonPadding", 8)); - - add(mTextField); - add(okButton); - - center(); - setVisible(true); - okButton->requestFocus(); -} - -void EditDialog::action(const gcn::ActionEvent &event) -{ - // Proxy button events to our listeners - FOR_EACH (ActionListenerIterator, i, mActionListeners) - (*i)->action(event); - - if (event.getId() == mEventOk) - scheduleDelete(); -} diff --git a/src/gui/editdialog.h b/src/gui/editdialog.h deleted file mode 100644 index 6d3d191bc..000000000 --- a/src/gui/editdialog.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 Andrei Karas - * Copyright (C) 2011-2013 The ManaPlus developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_EDITDIALOG_H -#define GUI_EDITDIALOG_H - -#include "localconsts.h" - -#include "gui/widgets/window.h" -#include "gui/widgets/textfield.h" - -#include - -#define ACTION_EDIT_OK "edit ok" - -/** - * An 'Ok' button dialog. - * - * \ingroup GUI - */ -class EditDialog final : public Window, public gcn::ActionListener -{ - public: - /** - * Constructor. - * - * @see Window::Window - */ - EditDialog(const std::string &title, const std::string &msg, - const std::string &eventOk = ACTION_EDIT_OK, - const int width = 300, Window *const parent = nullptr, - const bool modal = true); - - A_DELETE_COPY(EditDialog) - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - std::string getMsg() const A_WARN_UNUSED - { return mTextField->getText(); } - - private: - std::string mEventOk; - - TextField *mTextField; -}; - -#endif // GUI_EDITDIALOG_H diff --git a/src/gui/editserverdialog.cpp b/src/gui/editserverdialog.cpp deleted file mode 100644 index ff1d42eea..000000000 --- a/src/gui/editserverdialog.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2011-2012 The Mana Developers - * Copyright (C) 2012-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/editserverdialog.h" - -#include "input/keydata.h" -#include "input/keyevent.h" - -#include "gui/okdialog.h" -#include "gui/serverdialog.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/dropdown.h" -#include "gui/widgets/label.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/textfield.h" - -#include "utils/gettext.h" - -std::string TypeListModel::getElementAt(int elementIndex) -{ - if (elementIndex == 0) - return "TmwAthena"; - else if (elementIndex == 1) - return "Evol"; -#ifdef EATHENA_SUPPORT - else if (elementIndex == 2) - return "eAthena"; -#ifdef MANASERV_SUPPORT - else if (elementIndex == 3) - return "ManaServ"; -#endif -#else -#ifdef MANASERV_SUPPORT - else if (elementIndex == 2) - return "ManaServ"; -#endif -#endif - else - return "Unknown"; -} - -EditServerDialog::EditServerDialog(ServerDialog *const parent, - ServerInfo server, - const int index) : - // TRANSLATORS: edit server dialog name - Window(_("Edit Server"), true, parent), - gcn::ActionListener(), - gcn::KeyListener(), - mServerAddressField(new TextField(this, std::string())), - mPortField(new TextField(this, std::string())), - mNameField(new TextField(this, std::string())), - mDescriptionField(new TextField(this, std::string())), - mOnlineListUrlField(new TextField(this, std::string())), - // TRANSLATORS: edit server dialog button - mConnectButton(new Button(this, _("Connect"), "connect", this)), - // TRANSLATORS: edit server dialog button - mOkButton(new Button(this, _("OK"), "addServer", this)), - // TRANSLATORS: edit server dialog button - mCancelButton(new Button(this, _("Cancel"), "cancel", this)), - mTypeListModel(new TypeListModel), - mTypeField(new DropDown(this, mTypeListModel, false, true)), - mServerDialog(parent), - mServer(server), - mIndex(index) -{ - setWindowName("EditServerDialog"); - - // TRANSLATORS: edit server dialog label - Label *const nameLabel = new Label(this, _("Name:")); - // TRANSLATORS: edit server dialog label - Label *const serverAdressLabel = new Label(this, _("Address:")); - // TRANSLATORS: edit server dialog label - Label *const portLabel = new Label(this, _("Port:")); - // TRANSLATORS: edit server dialog label - Label *const typeLabel = new Label(this, _("Server type:")); - // TRANSLATORS: edit server dialog label - Label *const descriptionLabel = new Label(this, _("Description:")); - // TRANSLATORS: edit server dialog label - Label *const onlineListUrlLabel = new Label(this, _("Online list url:")); - mPortField->setNumeric(true); - mPortField->setRange(1, 65535); - - mTypeField->setSelected(0); // TmwAthena by default - - mServerAddressField->addActionListener(this); - mPortField->addActionListener(this); - - place(0, 0, nameLabel); - place(1, 0, mNameField, 4).setPadding(3); - place(0, 1, serverAdressLabel); - place(1, 1, mServerAddressField, 4).setPadding(3); - place(0, 2, portLabel); - place(1, 2, mPortField, 4).setPadding(3); - place(0, 3, typeLabel); - place(1, 3, mTypeField).setPadding(3); - place(0, 4, descriptionLabel); - place(1, 4, mDescriptionField, 4).setPadding(3); - place(0, 5, onlineListUrlLabel); - place(1, 5, mOnlineListUrlField, 4).setPadding(3); - place(0, 6, mConnectButton); - place(4, 6, mOkButton); - place(3, 6, mCancelButton); - - // Do this manually instead of calling reflowLayout so we can enforce a - // minimum width. - int width = 0; - int height = 0; - getLayout().reflow(width, height); - if (width < 300) - { - width = 300; - getLayout().reflow(width, height); - } - if (height < 120) - { - height = 120; - getLayout().reflow(width, height); - } - - setContentSize(width, height); - - setMinWidth(getWidth()); - setMinHeight(getHeight()); - setDefaultSize(getWidth(), getHeight(), ImageRect::CENTER); - - setResizable(false); - addKeyListener(this); - - loadWindowState(); - - mNameField->setText(mServer.name); - mDescriptionField->setText(mServer.description); - mOnlineListUrlField->setText(mServer.onlineListUrl); - mServerAddressField->setText(mServer.hostname); - mPortField->setText(toString(mServer.port)); - - switch (mServer.type) - { -#ifdef EATHENA_SUPPORT - case ServerInfo::EATHENA: - mTypeField->setSelected(2); - break; - case ServerInfo::MANASERV: -#ifdef MANASERV_SUPPORT - mTypeField->setSelected(3); - break; -#endif -#else - case ServerInfo::MANASERV: -#ifdef MANASERV_SUPPORT - mTypeField->setSelected(2); - break; -#endif -#endif - default: - case ServerInfo::UNKNOWN: - case ServerInfo::TMWATHENA: -#ifndef EATHENA_SUPPORT - case ServerInfo::EATHENA: -#endif - mTypeField->setSelected(0); - break; - case ServerInfo::EVOL: - mTypeField->setSelected(1); - break; - } - - setLocationRelativeTo(getParentWindow()); - setVisible(true); - - mNameField->requestFocus(); -} - -EditServerDialog::~EditServerDialog() -{ - delete mTypeListModel; -} - -void EditServerDialog::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - - if (eventId == "ok") - { - // Give focus back to the server dialog. - mServerAddressField->requestFocus(); - } - if (eventId == "addServer" || eventId == "connect") - { - // Check the given information - if (mServerAddressField->getText().empty() - || mPortField->getText().empty()) - { - // TRANSLATORS: edit server dialog error header - OkDialog *const dlg = new OkDialog(_("Error"), - // TRANSLATORS: edit server dialog error message - _("Please at least type both the address and the port " - "of the server."), DIALOG_ERROR); - dlg->addActionListener(this); - } - else - { - mCancelButton->setEnabled(false); - mOkButton->setEnabled(false); - - mServer.name = mNameField->getText(); - mServer.description = mDescriptionField->getText(); - mServer.onlineListUrl = mOnlineListUrlField->getText(); - mServer.hostname = mServerAddressField->getText(); - mServer.port = static_cast(atoi( - mPortField->getText().c_str())); - - if (mTypeField) - { - switch (mTypeField->getSelected()) - { - case 0: - mServer.type = ServerInfo::TMWATHENA; - break; - case 1: - mServer.type = ServerInfo::EVOL; - break; -#ifdef EATHENA_SUPPORT - case 2: - mServer.type = ServerInfo::EATHENA; - break; -#ifdef MANASERV_SUPPORT - case 3: - mServer.type = ServerInfo::MANASERV; - break; -#endif -#else -#ifdef MANASERV_SUPPORT - case 2: - mServer.type = ServerInfo::MANASERV; - break; -#endif -#endif - default: - mServer.type = ServerInfo::UNKNOWN; - } - } - else - { - mServer.type = ServerInfo::TMWATHENA; - } - - // Tell the server has to be saved - mServer.save = true; - - // Add server - mServerDialog->updateServer(mServer, mIndex); - if (eventId == "connect") - mServerDialog->connectToSelectedServer(); - scheduleDelete(); - } - } - else if (eventId == "cancel") - { - scheduleDelete(); - } -} - -void EditServerDialog::keyPressed(gcn::KeyEvent &keyEvent) -{ - if (keyEvent.isConsumed()) - return; - - const int actionId = static_cast( - &keyEvent)->getActionId(); - - if (actionId == static_cast(Input::KEY_GUI_CANCEL)) - { - scheduleDelete(); - } - else if (actionId == static_cast(Input::KEY_GUI_SELECT) - || actionId == static_cast(Input::KEY_GUI_SELECT2)) - { - action(gcn::ActionEvent(nullptr, mOkButton->getActionEventId())); - } -} diff --git a/src/gui/editserverdialog.h b/src/gui/editserverdialog.h deleted file mode 100644 index 531bb009a..000000000 --- a/src/gui/editserverdialog.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * The Mana Client - * Copyright (C) 2011-2012 The Mana Developers - * Copyright (C) 2012-2013 The ManaPlus Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_EDITSERVERDIALOG_H -#define GUI_EDITSERVERDIALOG_H - -class Button; -class TextField; -class DropDown; -class ServerDialog; - -#include "gui/widgets/window.h" - -#include "net/serverinfo.h" - -#include -#include -#include - -/** - * Server Type List Model - */ -class TypeListModel : public gcn::ListModel -{ - public: - TypeListModel() - { } - - /** - * Used to get number of line in the list - */ - int getNumberOfElements() override A_WARN_UNUSED -#ifdef EATHENA_SUPPORT -#ifdef MANASERV_SUPPORT - { return 4; } -#else - { return 3; } -#endif -#else -#ifdef MANASERV_SUPPORT - { return 3; } -#else - { return 2; } -#endif -#endif - - /** - * Used to get an element from the list - */ - std::string getElementAt(int elementIndex) override A_WARN_UNUSED; -}; - -/** - * The custom server addition dialog. - * - * \ingroup Interface - */ -class EditServerDialog final : public Window, - public gcn::ActionListener, - public gcn::KeyListener -{ - public: - EditServerDialog(ServerDialog *const parent, ServerInfo server, - const int index); - - A_DELETE_COPY(EditServerDialog) - - ~EditServerDialog(); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - void keyPressed(gcn::KeyEvent &keyEvent) override; - - private: - TextField *mServerAddressField; - TextField *mPortField; - TextField *mNameField; - TextField *mDescriptionField; - TextField *mOnlineListUrlField; - Button *mConnectButton; - Button *mOkButton; - Button *mCancelButton; - - TypeListModel *mTypeListModel; - DropDown *mTypeField; - - ServerDialog *mServerDialog; - ServerInfo mServer; - int mIndex; -}; - -#endif // GUI_EDITSERVERDIALOG_H diff --git a/src/gui/emotewindow.cpp b/src/gui/emotewindow.cpp deleted file mode 100644 index 848c1e88f..000000000 --- a/src/gui/emotewindow.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/emotewindow.h" - -#include "gui/widgets/colormodel.h" -#include "gui/widgets/colorpage.h" -#include "gui/widgets/emotepage.h" -#include "gui/widgets/namesmodel.h" -#include "gui/widgets/scrollarea.h" -#include "gui/widgets/tabbedarea.h" - -#include "utils/gettext.h" - -#include "resources/image.h" -#include "resources/imageset.h" - -#include "debug.h" - -static const int fontSizeListSize = 2; - -static const char *const fontSizeList[] = -{ - // TRANSLATORS: font size - N_("Normal font"), - // TRANSLATORS: font size - N_("Bold font"), -}; - -EmoteWindow::EmoteWindow() : - // TRANSLATORS: emotes window name - Window(_("Emotes"), false, nullptr, "emotes.xml"), - mTabs(new TabbedArea(this)), - mEmotePage(new EmotePage(this)), - mColorModel(ColorModel::createDefault(this)), - mColorPage(new ColorPage(this, mColorModel, "colorpage.xml")), - mScrollColorPage(new ScrollArea(mColorPage, false, "emotepage.xml")), - mFontModel(new NamesModel), - mFontPage(new ListBox(this, mFontModel, "")), - mScrollFontPage(new ScrollArea(mFontPage, false, "fontpage.xml")), - mImageSet(Theme::getImageSetFromThemeXml("emotetabs.xml", "", 17, 16)) -{ - setShowTitle(false); - setResizable(true); - - addMouseListener(this); - const int pad2 = mPadding * 2; - const int width = 200; - const int height = 150; - setWidth(width + pad2); - setHeight(height + pad2); - add(mTabs); - mTabs->setPosition(mPadding, mPadding); - mTabs->setWidth(width); - mTabs->setHeight(height); - center(); - - setTitleBarHeight(getPadding() + getTitlePadding()); - mScrollColorPage->setVerticalScrollPolicy(ScrollArea::SHOW_ALWAYS); - mScrollColorPage->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); - mScrollFontPage->setVerticalScrollPolicy(ScrollArea::SHOW_NEVER); - mScrollFontPage->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); - - mFontModel->fillFromArray(&fontSizeList[0], fontSizeListSize); - mFontPage->setCenter(true); - - if (mImageSet && mImageSet->size() >= 3) - { - for (int f = 0; f < 3; f ++) - { - Image *const image = mImageSet->get(f); - if (image) - image->incRef(); - } - - mTabs->addTab(mImageSet->get(0), mEmotePage); - mTabs->addTab(mImageSet->get(2), mScrollColorPage); - mTabs->addTab(mImageSet->get(1), mScrollFontPage); - } - else - { - // TRANSLATORS: emotes tab name - mTabs->addTab(_("Emotes"), mEmotePage); - // TRANSLATORS: emotes tab name - mTabs->addTab(_("Colors"), mScrollColorPage); - // TRANSLATORS: emotes tab name - mTabs->addTab(_("Fonts"), mScrollFontPage); - } - - mEmotePage->setActionEventId("emote"); - mColorPage->setActionEventId("color"); - mFontPage->setActionEventId("font"); -} - -EmoteWindow::~EmoteWindow() -{ - mTabs->removeAll(false); - mTabs->removeTab(mTabs->getTabByIndex(0)); - delete mEmotePage; - mEmotePage = nullptr; - delete mColorPage; - mColorPage = nullptr; - delete mColorModel; - mColorModel = nullptr; - delete mScrollColorPage; - mScrollColorPage = nullptr; - delete mFontPage; - mFontPage = nullptr; - delete mFontModel; - mFontModel = nullptr; - delete mScrollFontPage; - mScrollFontPage = nullptr; - if (mImageSet) - { - mImageSet->decRef(); - mImageSet = nullptr; - } -} - -void EmoteWindow::show() -{ - setVisible(true); -} - -void EmoteWindow::hide() -{ - setVisible(false); -} - -std::string EmoteWindow::getSelectedEmote() const -{ - const int index = mEmotePage->getSelectedIndex(); - if (index < 0) - return std::string(); - - char chr[2]; - chr[0] = '0' + index; - chr[1] = 0; - return std::string("%%").append(&chr[0]); -} - -void EmoteWindow::clearEmote() -{ - const int index = mEmotePage->getSelectedIndex(); - mEmotePage->resetAction(); - if (index >= 0) - setVisible(false); -} - -std::string EmoteWindow::getSelectedColor() const -{ - const int index = mColorPage->getSelected(); - if (index < 0) - return std::string(); - - char chr[2]; - chr[0] = '0' + index; - chr[1] = 0; - return std::string("##").append(&chr[0]); -} - -void EmoteWindow::clearColor() -{ - mColorPage->resetAction(); - setVisible(false); -} - -std::string EmoteWindow::getSelectedFont() const -{ - const int index = mFontPage->getSelected(); - if (index < 0) - return std::string(); - - if (!index) - return "##b"; - else - return "##B"; -} - -void EmoteWindow::clearFont() -{ - mFontPage->setSelected(-1); - setVisible(false); -} - -void EmoteWindow::addListeners(gcn::ActionListener *const listener) -{ - mEmotePage->addActionListener(listener); - mColorPage->addActionListener(listener); - mFontPage->addActionListener(listener); -} - -void EmoteWindow::widgetResized(const gcn::Event &event) -{ - Window::widgetResized(event); - const int pad2 = mPadding * 2; - const int width = mDimension.width; - const int height = mDimension.height; - - mTabs->setSize(width - pad2, height - pad2); - mTabs->adjustWidget(mEmotePage); - mTabs->adjustWidget(mScrollColorPage); - mColorPage->setSize(mScrollColorPage->getWidth(), - mScrollColorPage->getHeight()); - mEmotePage->widgetResized(event); -} - -void EmoteWindow::widgetMoved(const gcn::Event &event) -{ - Window::widgetMoved(event); - mEmotePage->widgetResized(event); -} diff --git a/src/gui/emotewindow.h b/src/gui/emotewindow.h deleted file mode 100644 index b65c0c13c..000000000 --- a/src/gui/emotewindow.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_EMOTEWINDOW_H -#define GUI_EMOTEWINDOW_H - -#include "gui/widgets/window.h" - -class ColorModel; -class ColorPage; -class EmotePage; -class ImageSet; -class ListBox; -class NamesModel; -class ScrollArea; -class TabbedArea; - -class EmoteWindow final : public Window -{ - public: - EmoteWindow(); - - A_DELETE_COPY(EmoteWindow) - - ~EmoteWindow(); - - void show(); - - void hide(); - - std::string getSelectedEmote() const; - - void clearEmote(); - - std::string getSelectedColor() const; - - void clearColor(); - - std::string getSelectedFont() const; - - void clearFont(); - - void addListeners(gcn::ActionListener *const listener); - - void widgetResized(const gcn::Event &event) override; - - void widgetMoved(const gcn::Event &event) override; - - private: - TabbedArea *mTabs; - EmotePage *mEmotePage; - ColorModel *mColorModel; - ColorPage *mColorPage; - ScrollArea *mScrollColorPage; - NamesModel *mFontModel; - ListBox *mFontPage; - ScrollArea *mScrollFontPage; - ImageSet *mImageSet; -}; - -extern EmoteWindow *emoteWindow; - -#endif // GUI_EMOTEWINDOW_H diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp deleted file mode 100644 index 9e4438393..000000000 --- a/src/gui/equipmentwindow.cpp +++ /dev/null @@ -1,668 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/equipmentwindow.h" - -#include "configuration.h" -#include "dragdrop.h" -#include "graphicsvertexes.h" -#include "inventory.h" -#include "item.h" - -#include "being/being.h" -#include "being/localplayer.h" -#include "being/playerinfo.h" - -#include "gui/itempopup.h" -#include "gui/setup.h" -#include "gui/viewport.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/playerbox.h" - -#include "net/inventoryhandler.h" -#include "net/net.h" - -#include "resources/imageset.h" - -#include "utils/dtor.h" -#include "utils/gettext.h" - -#include - -#include - -#include "debug.h" - -static const int BOX_COUNT = 13; - -EquipmentWindow::EquipmentWindow(Equipment *const equipment, - Being *const being, - const bool foring): - // TRANSLATORS: equipment window name - Window(_("Equipment"), false, nullptr, "equipment.xml"), - gcn::ActionListener(), - mEquipment(equipment), - mItemPopup(new ItemPopup), - mPlayerBox(new PlayerBox("equipment_playerbox.xml", - "equipment_selectedplayerbox.xml")), - // TRANSLATORS: equipment window button - mUnequip(new Button(this, _("Unequip"), "unequip", this)), - mSelected(-1), - mForing(foring), - mImageSet(nullptr), - mBeing(being), - mBoxes(), - mHighlightColor(getThemeColor(Theme::HIGHLIGHT)), - mBorderColor(getThemeColor(Theme::BORDER)), - mLabelsColor(getThemeColor(Theme::LABEL)), - mLabelsColor2(getThemeColor(Theme::LABEL_OUTLINE)), - mSlotBackground(), - mSlotHighlightedBackground(), - mVertexes(new ImageCollection), - mItemPadding(getOption("itemPadding")), - mBoxSize(getOption("boxSize")), - mButtonPadding(getOption("buttonPadding", 5)), - mMinX(180), - mMinY(345), - mMaxX(0), - mMaxY(0) -{ - if (setupWindow) - setupWindow->registerWindowForReset(this); - - if (!mBoxSize) - mBoxSize = 36; - - // Control that shows the Player - mPlayerBox->setDimension(gcn::Rectangle(50, 80, 74, 168)); - mPlayerBox->setPlayer(being); - - if (foring) - setWindowName("Being equipment"); - else - setWindowName("Equipment"); - - setCloseButton(true); - setSaveVisible(true); - setStickyButtonLock(true); - - mBoxes.reserve(BOX_COUNT); - for (int f = 0; f < BOX_COUNT; f ++) - mBoxes.push_back(nullptr); - - fillBoxes(); - recalcSize(); - - loadWindowState(); - - const gcn::Rectangle &area = getChildrenArea(); - mUnequip->setPosition(area.width - mUnequip->getWidth() - mButtonPadding, - area.height - mUnequip->getHeight() - mButtonPadding); - mUnequip->setEnabled(false); - - ImageRect rect; - Theme::instance()->loadRect(rect, "equipment_background.xml", "", 0, 1); - mSlotBackground = rect.grid[0]; - mSlotHighlightedBackground = rect.grid[1]; - add(mPlayerBox); - add(mUnequip); - enableVisibleSound(true); -} - -EquipmentWindow::~EquipmentWindow() -{ - delete mItemPopup; - mItemPopup = nullptr; - if (this == beingEquipmentWindow) - { - if (mEquipment) - delete mEquipment->getBackend(); - delete mEquipment; - mEquipment = nullptr; - } - delete_all(mBoxes); - mBoxes.clear(); - if (mImageSet) - { - mImageSet->decRef(); - mImageSet = nullptr; - } - if (mSlotBackground) - mSlotBackground->decRef(); - if (mSlotHighlightedBackground) - mSlotHighlightedBackground->decRef(); - delete mVertexes; - mVertexes = nullptr; -} - -void EquipmentWindow::draw(gcn::Graphics *graphics) -{ - BLOCK_START("EquipmentWindow::draw") - // Draw window graphics - Window::draw(graphics); - Graphics *const g = static_cast(graphics); - - int i = 0; - gcn::Font *const font = getFont(); - const int fontHeight = font->getHeight(); - - if (openGLMode != RENDER_SAFE_OPENGL) - { - if (mLastRedraw) - { - mVertexes->clear(); - FOR_EACH (std::vector::const_iterator, it, mBoxes) - { - const EquipmentBox *const box = *it; - if (!box) - continue; - if (i == mSelected) - { - g->calcTile(mVertexes, mSlotHighlightedBackground, - box->x, box->y); - } - else - { - g->calcTile(mVertexes, mSlotBackground, box->x, box->y); - } - } - } - g->drawTile(mVertexes); - } - else - { - for (std::vector::const_iterator it = mBoxes.begin(), - it_end = mBoxes.end(); it != it_end; ++ it, ++ i) - { - const EquipmentBox *const box = *it; - if (!box) - continue; - if (i == mSelected) - g->drawImage(mSlotHighlightedBackground, box->x, box->y); - else - g->drawImage(mSlotBackground, box->x, box->y); - } - } - - if (!mEquipment) - { - BLOCK_END("EquipmentWindow::draw") - return; - } - - i = 0; - for (std::vector::const_iterator it = mBoxes.begin(), - it_end = mBoxes.end(); it != it_end; ++ it, ++ i) - { - const EquipmentBox *const box = *it; - if (!box) - continue; - const Item *const item = mEquipment->getEquipment(i); - if (item) - { - // Draw Item. - Image *const image = item->getImage(); - if (image) - { - image->setAlpha(1.0F); // Ensure the image is drawn - // with maximum opacity - g->drawImage(image, box->x + mItemPadding, - box->y + mItemPadding); - if (i == EQUIP_PROJECTILE_SLOT) - { - g->setColorAll(mLabelsColor, mLabelsColor2); - const std::string str = toString(item->getQuantity()); - font->drawString(g, str, - box->x + (mBoxSize - font->getWidth(str)) / 2, - box->y - fontHeight); - } - } - } - else if (box->image) - { - g->drawImage(box->image, box->x + mItemPadding, - box->y + mItemPadding); - } - } - BLOCK_END("EquipmentWindow::draw") -} - -void EquipmentWindow::action(const gcn::ActionEvent &event) -{ - if (!mEquipment) - return; - - if (event.getId() == "unequip" && mSelected > -1) - { - const Item *const item = mEquipment->getEquipment(mSelected); - Net::getInventoryHandler()->unequipItem(item); - setSelected(-1); - } -} - -Item *EquipmentWindow::getItem(const int x, const int y) const -{ - if (!mEquipment) - return nullptr; - - int i = 0; - - for (std::vector::const_iterator it = mBoxes.begin(), - it_end = mBoxes.end(); it != it_end; ++ it, ++ i) - { - const EquipmentBox *const box = *it; - if (!box) - continue; - const gcn::Rectangle tRect(box->x, box->y, mBoxSize, mBoxSize); - - if (tRect.isPointInRect(x, y)) - return mEquipment->getEquipment(i); - } - return nullptr; -} - -void EquipmentWindow::mousePressed(gcn::MouseEvent& mouseEvent) -{ - if (!mEquipment) - { - Window::mousePressed(mouseEvent); - return; - } - - const int x = mouseEvent.getX(); - const int y = mouseEvent.getY(); - - if (mouseEvent.getButton() == gcn::MouseEvent::LEFT) - { - if (mForing) - { - Window::mousePressed(mouseEvent); - return; - } - // Checks if any of the presses were in the equip boxes. - int i = 0; - - bool inBox(false); - - for (std::vector::const_iterator it = mBoxes.begin(), - it_end = mBoxes.end(); it != it_end; ++ it, ++ i) - { - const EquipmentBox *const box = *it; - if (!box) - continue; - const Item *const item = mEquipment->getEquipment(i); - const gcn::Rectangle tRect(box->x, box->y, mBoxSize, mBoxSize); - - if (tRect.isPointInRect(x, y)) - { - inBox = true; - if (item) - { - setSelected(i); - dragDrop.dragItem(item, DRAGDROP_SOURCE_EQUIPMENT); - return; - } - } - if (inBox) - return; - } - } - else if (mouseEvent.getButton() == gcn::MouseEvent::RIGHT) - { - if (Item *const item = getItem(x, y)) - { - if (mItemPopup) - mItemPopup->setVisible(false); - - /* Convert relative to the window coordinates to absolute screen - * coordinates. - */ - const int mx = x + getX(); - const int my = y + getY(); - if (viewport) - { - if (mForing) - viewport->showUndressPopup(mx, my, mBeing, item); - else - viewport->showPopup(this, mx, my, item, true); - } - } - } - Window::mousePressed(mouseEvent); -} - -void EquipmentWindow::mouseReleased(gcn::MouseEvent &mouseEvent) -{ - Window::mouseReleased(mouseEvent); - const DragDropSource src = dragDrop.getSource(); - if (dragDrop.isEmpty() || (src != DRAGDROP_SOURCE_INVENTORY - && src != DRAGDROP_SOURCE_EQUIPMENT)) - { - return; - } - Inventory *const inventory = player_node - ? PlayerInfo::getInventory() : nullptr; - if (!inventory) - return; - - Item *const item = inventory->findItem(dragDrop.getItem(), - dragDrop.getItemColor()); - if (!item) - return; - - if (dragDrop.getSource() == DRAGDROP_SOURCE_INVENTORY) - { - if (item->isEquipment()) - { - if (!item->isEquipped()) - Net::getInventoryHandler()->equipItem(item); - } - } - else if (dragDrop.getSource() == DRAGDROP_SOURCE_EQUIPMENT) - { - if (item->isEquipment()) - { - const int x = mouseEvent.getX(); - const int y = mouseEvent.getY(); - int i = 0; - for (std::vector::const_iterator - it = mBoxes.begin(), it_end = mBoxes.end(); - it != it_end; ++ it, ++ i) - { - const EquipmentBox *const box = *it; - if (!box) - continue; - const gcn::Rectangle tRect(box->x, box->y, mBoxSize, mBoxSize); - - if (tRect.isPointInRect(x, y)) - return; - } - - if (item->isEquipped()) - Net::getInventoryHandler()->unequipItem(item); - } - } - dragDrop.clear(); - dragDrop.deselect(); -} - -// Show ItemTooltip -void EquipmentWindow::mouseMoved(gcn::MouseEvent &event) -{ - Window::mouseMoved(event); - - if (!mItemPopup) - return; - - const int x = event.getX(); - const int y = event.getY(); - - const Item *const item = getItem(x, y); - - if (item) - { - int mouseX, mouseY; - SDL_GetMouseState(&mouseX, &mouseY); - - mItemPopup->setItem(item); - mItemPopup->position(x + getX(), y + getY()); - } - else - { - mItemPopup->setVisible(false); - } -} - -// Hide ItemTooltip -void EquipmentWindow::mouseExited(gcn::MouseEvent &event A_UNUSED) -{ - if (mItemPopup) - mItemPopup->setVisible(false); -} - -void EquipmentWindow::setSelected(const int index) -{ - mSelected = index; - mRedraw = true; - if (mUnequip) - mUnequip->setEnabled(mSelected != -1); - if (mItemPopup) - mItemPopup->setVisible(false); -} - -void EquipmentWindow::setBeing(Being *const being) -{ - mPlayerBox->setPlayer(being); - mBeing = being; - if (mEquipment) - delete mEquipment->getBackend(); - delete mEquipment; - if (!being) - { - mEquipment = nullptr; - return; - } - mEquipment = being->getEquipment(); -} - -void EquipmentWindow::updateBeing(Being *const being) -{ - if (being == mBeing) - setBeing(being); -} - -void EquipmentWindow::resetBeing(const Being *const being) -{ - if (being == mBeing) - setBeing(nullptr); -} - -void EquipmentWindow::fillBoxes() -{ - XML::Document *const doc = new XML::Document( - paths.getStringValue("equipmentWindowFile")); - const XmlNodePtr root = doc->rootNode(); - if (!root) - { - delete doc; - fillDefault(); - return; - } - - if (mImageSet) - mImageSet->decRef(); - - mImageSet = Theme::getImageSetFromTheme(XML::getProperty( - root, "image", "equipmentbox.png"), 32, 32); - - for_each_xml_child_node(node, root) - { - if (xmlNameEqual(node, "playerbox")) - loadPlayerBox(node); - else if (xmlNameEqual(node, "slot")) - loadSlot(node, mImageSet); - } - delete doc; -} - -void EquipmentWindow::loadPlayerBox(const XmlNodePtr playerBoxNode) -{ - mPlayerBox->setDimension(gcn::Rectangle( - XML::getProperty(playerBoxNode, "x", 50), - XML::getProperty(playerBoxNode, "y", 80), - XML::getProperty(playerBoxNode, "width", 74), - XML::getProperty(playerBoxNode, "height", 168))); -} - -void EquipmentWindow::loadSlot(const XmlNodePtr slotNode, - const ImageSet *const imageset) -{ - const int slot = parseSlotName(XML::getProperty(slotNode, "name", "")); - if (slot < 0) - return; - - const int x = XML::getProperty(slotNode, "x", 0) + getPadding(); - const int y = XML::getProperty(slotNode, "y", 0) + getTitleBarHeight(); - const int imageIndex = XML::getProperty(slotNode, "image", -1); - Image *image = nullptr; - - if (imageset && imageIndex >= 0 && imageIndex - < static_cast(imageset->size())) - { - image = imageset->get(imageIndex); - } - - if (mBoxes[slot]) - { - EquipmentBox *const box = mBoxes[slot]; - box->x = x; - box->y = y; - box->image = image; - } - else - { - mBoxes[slot] = new EquipmentBox(x, y, image); - } - if (x < mMinX) - mMinX = x; - if (y < mMinY) - mMinY = y; - if (x + mBoxSize > mMaxX) - mMaxX = x + mBoxSize; - if (y + mBoxSize > mMaxY) - mMaxY = y + mBoxSize; -} - -int EquipmentWindow::parseSlotName(const std::string &name) const -{ - int id = -1; - if (name == "shoes" || name == "boot" || name == "boots") - { - id = 4; - } - else if (name == "bottomclothes" || name == "bottom" || name == "pants") - { - id = 3; - } - else if (name == "topclothes" || name == "top" - || name == "torso" || name == "body") - { - id = 0; - } - else if (name == "misc1" || name == "cape") - { - id = 5; - } - else if (name == "misc2" || name == "scarf" || name == "scarfs") - { - id = 7; - } - else if (name == "hat" || name == "hats") - { - id = 2; - } - else if (name == "wings") - { - id = 6; - } - else if (name == "glove" || name == "gloves") - { - id = 1; - } - else if (name == "weapon" || name == "weapons") - { - id = 8; - } - else if (name == "shield" || name == "shields") - { - id = 9; - } - else if (name == "amulet" || name == "amulets") - { - id = 11; - } - else if (name == "ring" || name == "rings") - { - id = 12; - } - else if (name == "arrow" || name == "arrows" || name == "ammo") - { - id = 10; - } - - return id; -} - -void EquipmentWindow::fillDefault() -{ - if (mImageSet) - mImageSet->decRef(); - - mImageSet = Theme::getImageSetFromTheme( - "equipmentbox.png", 32, 32); - - addBox(0, 90, 40, 0); // torso - addBox(1, 8, 78, 1); // gloves - addBox(2, 70, 0, 2); // hat - addBox(3, 50, 253, 3); // pants - addBox(4, 90, 253, 4); // boots - addBox(5, 8, 213, 5); // FREE - addBox(6, 129, 213, 6); // wings - addBox(7, 50, 40, 5); // scarf - addBox(8, 8, 168, 7); // weapon - addBox(9, 129, 168, 8); // shield - addBox(10, 129, 78, 9); // ammo - addBox(11, 8, 123, 5); // amulet - addBox(12, 129, 123, 5); // ring -} - -void EquipmentWindow::addBox(const int idx, int x, int y, const int imageIndex) -{ - Image *image = nullptr; - - if (mImageSet && imageIndex >= 0 && imageIndex - < static_cast(mImageSet->size())) - { - image = mImageSet->get(imageIndex); - } - - x += getPadding(); - y += getTitleBarHeight(); - mBoxes[idx] = new EquipmentBox(x, y, image); - - if (x < mMinX) - mMinX = x; - if (y < mMinY) - mMinY = y; - if (x + mBoxSize > mMaxX) - mMaxX = x + mBoxSize; - if (y + mBoxSize > mMaxY) - mMaxY = y + mBoxSize; -} - -void EquipmentWindow::recalcSize() -{ - mMaxX += mMinX; - mMaxY += mMinY + mUnequip->getHeight() + mButtonPadding; - setDefaultSize(mMaxX, mMaxY, ImageRect::CENTER); -} diff --git a/src/gui/equipmentwindow.h b/src/gui/equipmentwindow.h deleted file mode 100644 index 5fd69c23a..000000000 --- a/src/gui/equipmentwindow.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_EQUIPMENTWINDOW_H -#define GUI_EQUIPMENTWINDOW_H - -#include "equipment.h" -#include "localconsts.h" - -#include "gui/widgets/window.h" - -#include "utils/xml.h" - -#include - -#include - -class Being; -class Button; -class Image; -class ImageSet; -class Item; -class ItemPopup; -class PlayerBox; - -struct EquipmentBox final -{ - EquipmentBox(const int x0, const int y0, Image *const img) : - x(x0), y(y0), image(img) - { } - - A_DELETE_COPY(EquipmentBox) - - int x; - int y; - Image *image; -}; - -/** - * Equipment dialog. - * - * \ingroup Interface - */ -class EquipmentWindow final : public Window, public gcn::ActionListener -{ - public: - /** - * Constructor. - */ - EquipmentWindow(Equipment *const equipment, Being *const being, - const bool foring = false); - - A_DELETE_COPY(EquipmentWindow) - - /** - * Destructor. - */ - ~EquipmentWindow(); - - /** - * Draws the equipment window. - */ - void draw(gcn::Graphics *graphics) override; - - void action(const gcn::ActionEvent &event) override; - - void mousePressed(gcn::MouseEvent& mouseEvent) override; - - const Item* getEquipment(const int i) const A_WARN_UNUSED - { return mEquipment ? mEquipment->getEquipment(i) : nullptr; } - - void setBeing(Being *const being); - - void updateBeing(Being *const being); - - void resetBeing(const Being *const being); - - void mouseExited(gcn::MouseEvent &event) override; - - void mouseMoved(gcn::MouseEvent &event) override; - - void mouseReleased(gcn::MouseEvent &event) override; - - void recalcSize(); - - private: - Item *getItem(const int x, const int y) const A_WARN_UNUSED; - - void setSelected(const int index); - - void fillBoxes(); - - void fillDefault(); - - void addBox(const int idx, int x, int y, const int imageIndex); - - void loadWindow(const XmlNodePtr windowNode); - - void loadPlayerBox(const XmlNodePtr playerBoxNode); - - void loadSlot(const XmlNodePtr slotNode, - const ImageSet *const imageset); - - int parseSlotName(const std::string &name) const A_WARN_UNUSED; - - Equipment *mEquipment; - - ItemPopup *mItemPopup; - PlayerBox *mPlayerBox; - Button *mUnequip; - - int mSelected; /**< Index of selected item. */ - bool mForing; - ImageSet *mImageSet; - Being *mBeing; - std::vector mBoxes; - gcn::Color mHighlightColor; - gcn::Color mBorderColor; - gcn::Color mLabelsColor; - gcn::Color mLabelsColor2; - Image *mSlotBackground; - Image *mSlotHighlightedBackground; - ImageCollection *mVertexes; - int mItemPadding; - int mBoxSize; - int mButtonPadding; - int mMinX; - int mMinY; - int mMaxX; - int mMaxY; -}; - -extern EquipmentWindow *equipmentWindow; -extern EquipmentWindow *beingEquipmentWindow; - -#endif // GUI_EQUIPMENTWINDOW_H diff --git a/src/gui/helpwindow.cpp b/src/gui/helpwindow.cpp deleted file mode 100644 index 2f6eb5366..000000000 --- a/src/gui/helpwindow.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/helpwindow.h" - -#include "configuration.h" - -#include "gui/didyouknowwindow.h" -#include "gui/gui.h" -#include "gui/sdlfont.h" -#include "gui/setup.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/browserbox.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/scrollarea.h" - -#include "resources/resourcemanager.h" - -#include "utils/gettext.h" -#include "utils/paths.h" -#include "utils/process.h" - -#include "utils/translation/podict.h" -#include "utils/translation/translationmanager.h" - -#include "debug.h" - -HelpWindow::HelpWindow() : - // TRANSLATORS: help window name - Window(_("Help"), false, nullptr, "help.xml"), - gcn::ActionListener(), - // TRANSLATORS: help window. button. - mDYKButton(new Button(this, _("Did you know..."), "DYK", this)), - mBrowserBox(new BrowserBox(this)), - mScrollArea(new ScrollArea(mBrowserBox, true, "help_background.xml")), - mTagFileMap() -{ - setMinWidth(300); - setMinHeight(220); - setContentSize(455, 350); - setWindowName("Help"); - setCloseButton(true); - setResizable(true); - setStickyButtonLock(true); - - if (setupWindow) - setupWindow->registerWindowForReset(this); - - setDefaultSize(500, 400, ImageRect::CENTER); - - mBrowserBox->setOpaque(false); - - mBrowserBox->setLinkHandler(this); - mBrowserBox->setFont(gui->getHelpFont()); - mBrowserBox->setProcessVersion(true); - mBrowserBox->setEnableImages(true); - mBrowserBox->setEnableKeys(true); - mBrowserBox->setEnableTabs(true); - - place(4, 3, mDYKButton); - place(0, 0, mScrollArea, 5, 3).setPadding(3); - - Layout &layout = getLayout(); - layout.setRowHeight(0, Layout::AUTO_SET); - - loadWindowState(); - loadTags(); - enableVisibleSound(true); -} - -void HelpWindow::action(const gcn::ActionEvent &event) -{ - if (event.getId() == "DYK") - { - if (didYouKnowWindow) - { - didYouKnowWindow->setVisible(!didYouKnowWindow->isWindowVisible()); - if (didYouKnowWindow->isWindowVisible()) - didYouKnowWindow->requestMoveToTop(); - } - } -} - -void HelpWindow::handleLink(const std::string &link, - gcn::MouseEvent *event A_UNUSED) -{ - if (!strStartWith(link, "http://") && !strStartWith(link, "https://")) - { - std::string helpFile = link; - loadHelp(helpFile); - } - else - { - openBrowser(link); - } -} - -void HelpWindow::loadHelp(const std::string &helpFile) -{ - if (!checkPath(helpFile)) - return; - mBrowserBox->clearRows(); - loadFile("header"); - loadFile(helpFile); - loadFile("footer"); - mScrollArea->setVerticalScrollAmount(0); - setVisible(true); -} - -void HelpWindow::loadFile(std::string file) -{ - trim(file); - std::string helpPath = branding.getStringValue("helpPath"); - if (helpPath.empty()) - helpPath = paths.getStringValue("help"); - - StringVect lines; - TranslationManager::translateFile(helpPath.append(file).append(".txt"), - translator, lines); - - for (size_t i = 0, sz = lines.size(); i < sz; ++i) - mBrowserBox->addRow(lines[i]); -} - -void HelpWindow::loadTags() -{ - std::string helpPath = branding.getStringValue("helpPath"); - if (helpPath.empty()) - helpPath = paths.getStringValue("help"); - StringVect lines; - ResourceManager::loadTextFile(helpPath.append("tags.idx"), lines); - FOR_EACH (StringVectCIter, it, lines) - { - const std::string &str = *it; - const size_t idx = str.find('|'); - if (idx != std::string::npos) - mTagFileMap[str.substr(idx + 1)].insert(str.substr(0, idx)); - } -} - -void HelpWindow::search(const std::string &text0) -{ - std::string text = text0; - trim(text); - toLower(text); - if (mTagFileMap.find(text) == mTagFileMap.end()) - { - loadHelp("searchnotfound"); - } - else - { - const HelpNames &names = mTagFileMap[text]; - if (names.size() == 1) - { - loadHelp(*names.begin()); - } - else - { - if (!translator) - return; - mBrowserBox->clearRows(); - loadFile("header"); - loadFile("searchmany"); - FOR_EACH (HelpNamesCIter, it, names) - { - const char *const str = (*it).c_str(); - mBrowserBox->addRow(strprintf(" -> @@%s|%s@@", str, - translator->getChar(str))); - } - loadFile("footer"); - mScrollArea->setVerticalScrollAmount(0); - setVisible(true); - } - } -} diff --git a/src/gui/helpwindow.h b/src/gui/helpwindow.h deleted file mode 100644 index 1419e0a10..000000000 --- a/src/gui/helpwindow.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_HELPWINDOW_H -#define GUI_HELPWINDOW_H - -#include "gui/widgets/linkhandler.h" -#include "gui/widgets/window.h" - -#include - -#include "localconsts.h" - -#include -#include - -class Button; -class BrowserBox; -class ScrollArea; - -typedef std::set HelpNames; -typedef HelpNames::const_iterator HelpNamesCIter; -typedef std::map HelpTagsMap; - -/** - * The help window. - */ -class HelpWindow final : public Window, public LinkHandler, - public gcn::ActionListener -{ - public: - /** - * Constructor. - */ - HelpWindow(); - - A_DELETE_COPY(HelpWindow) - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - /** - * Handles link action. - */ - void handleLink(const std::string &link, - gcn::MouseEvent *event A_UNUSED) override; - - /** - * Loads help in the dialog. - */ - void loadHelp(const std::string &helpFile); - - /** - * Seach for given text in tags. - */ - void search(const std::string &text); - - private: - void loadTags(); - - void loadFile(std::string file); - - Button *mDYKButton; - - BrowserBox *mBrowserBox; - ScrollArea *mScrollArea; - HelpTagsMap mTagFileMap; -}; - -extern HelpWindow *helpWindow; - -#endif // GUI_HELPWINDOW_H diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp deleted file mode 100644 index d36c52e61..000000000 --- a/src/gui/inventorywindow.cpp +++ /dev/null @@ -1,833 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/inventorywindow.h" - -#include "configuration.h" -#include "item.h" -#include "units.h" - -#include "being/playerinfo.h" - -#include "input/inputmanager.h" -#include "input/keyevent.h" - -#include "gui/equipmentwindow.h" -#include "gui/gui.h" -#include "gui/itemamountwindow.h" -#include "gui/outfitwindow.h" -#include "gui/setup.h" -#include "gui/shopwindow.h" -#include "gui/textpopup.h" -#include "gui/tradewindow.h" -#include "gui/viewport.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/dropdown.h" -#include "gui/widgets/itemcontainer.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/progressbar.h" -#include "gui/widgets/scrollarea.h" -#include "gui/widgets/tabstrip.h" -#include "gui/widgets/textfield.h" - -#include "net/inventoryhandler.h" -#include "net/net.h" - -#include "resources/itemdb.h" - -#include "utils/gettext.h" - -#include - -#include - -#include "debug.h" - -static const char *const SORT_NAME_INVENTORY[6] = -{ - // TRANSLATORS: inventory sort mode - N_("default"), - // TRANSLATORS: inventory sort mode - N_("by name"), - // TRANSLATORS: inventory sort mode - N_("by id"), - // TRANSLATORS: inventory sort mode - N_("by weight"), - // TRANSLATORS: inventory sort mode - N_("by amount"), - // TRANSLATORS: inventory sort mode - N_("by type") -}; - -class SortListModelInv final : public gcn::ListModel -{ -public: - ~SortListModelInv() - { } - - int getNumberOfElements() override - { return 6; } - - std::string getElementAt(int i) override - { - if (i >= getNumberOfElements() || i < 0) - return "???"; - - return gettext(SORT_NAME_INVENTORY[i]); - } -}; - -InventoryWindow::WindowList InventoryWindow::invInstances; - -InventoryWindow::InventoryWindow(Inventory *const inventory): - Window("Inventory", false, nullptr, "inventory.xml"), - gcn::ActionListener(), - gcn::KeyListener(), - gcn::SelectionListener(), - InventoryListener(), - mInventory(inventory), - mItems(new ItemContainer(this, mInventory)), - mWeight(), - mSlots(), - mUseButton(nullptr), - mDropButton(nullptr), - mSplitButton(nullptr), - mOutfitButton(nullptr), - mShopButton(nullptr), - mEquipmentButton(nullptr), - mStoreButton(nullptr), - mRetrieveButton(nullptr), - mInvCloseButton(nullptr), - mWeightBar(nullptr), - mSlotsBar(new ProgressBar(this, 0.0F, 100, 0, Theme::PROG_INVY_SLOTS)), - mFilter(nullptr), - mSortModel(new SortListModelInv), - mSortDropDown(new DropDown(this, mSortModel, false, false, this, "sort")), - mNameFilter(new TextField(this, "", true, this, "namefilter", true)), - mSortDropDownCell(nullptr), - mNameFilterCell(nullptr), - mFilterCell(nullptr), - mSlotsBarCell(nullptr), - mTextPopup(new TextPopup), - mSplit(false), - mCompactMode(false) -{ - if (inventory) - { - setCaption(gettext(inventory->getName().c_str())); - setWindowName(inventory->getName()); - } - else - { - // TRANSLATORS: inventory window name - setCaption(_("Inventory")); - setWindowName("Inventory"); - } - - listen(CHANNEL_ATTRIBUTES); - - if (setupWindow) - setupWindow->registerWindowForReset(this); - - setResizable(true); - setCloseButton(true); - setSaveVisible(true); - setStickyButtonLock(true); - - if (mainGraphics->mWidth > 600) - setDefaultSize(450, 310, ImageRect::CENTER); - else - setDefaultSize(387, 307, ImageRect::CENTER); - setMinWidth(310); - setMinHeight(179); - addKeyListener(this); - - mItems->addSelectionListener(this); - - gcn::ScrollArea *const invenScroll = new ScrollArea( - mItems, getOptionBool("showbackground"), "inventory_background.xml"); - invenScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - - const int size = config.getIntValue("fontSize"); - mFilter = new TabStrip(this, "filter_" + getWindowName(), size + 16); - mFilter->addActionListener(this); - mFilter->setActionEventId("tag_"); - - mSortDropDown->setSelected(0); - - StringVect tags = ItemDB::getTags(); - const size_t sz = tags.size(); - for (size_t f = 0; f < sz; f ++) - mFilter->addButton(tags[f]); - - if (isMainInventory()) - { - // TRANSLATORS: inventory button - const std::string equip = _("Equip"); - // TRANSLATORS: inventory button - const std::string use = _("Use"); - // TRANSLATORS: inventory button - const std::string unequip = _("Unequip"); - - std::string longestUseString = getFont()->getWidth(equip) > - getFont()->getWidth(use) ? equip : use; - - if (getFont()->getWidth(longestUseString) < - getFont()->getWidth(unequip)) - { - longestUseString = unequip; - } - - mUseButton = new Button(this, longestUseString, "use", this); - // TRANSLATORS: inventory button - mDropButton = new Button(this, _("Drop..."), "drop", this); - // TRANSLATORS: inventory button - mSplitButton = new Button(this, _("Split"), "split", this); - // TRANSLATORS: inventory button - mOutfitButton = new Button(this, _("Outfits"), "outfit", this); - // TRANSLATORS: inventory button - mShopButton = new Button(this, _("Shop"), "shop", this); - // TRANSLATORS: inventory button - mEquipmentButton = new Button(this, _("Equipment"), "equipment", this); - mWeightBar = new ProgressBar(this, 0.0F, 100, 0, Theme::PROG_WEIGHT); - - place(0, 0, mWeightBar, 4); - mSlotsBarCell = &place(4, 0, mSlotsBar, 5); - mSortDropDownCell = &place(9, 0, mSortDropDown, 2); - - mFilterCell = &place(0, 1, mFilter, 10).setPadding(3); - mNameFilterCell = &place(9, 1, mNameFilter, 2); - - place(0, 2, invenScroll, 11).setPadding(3); - place(0, 3, mUseButton); - place(1, 3, mDropButton); - place(8, 2, mSplitButton); - place(8, 3, mShopButton); - place(9, 3, mOutfitButton); - place(10, 3, mEquipmentButton); - - updateWeight(); - } - else - { - // TRANSLATORS: storage button - mStoreButton = new Button(this, _("Store"), "store", this); - // TRANSLATORS: storage button - mRetrieveButton = new Button(this, _("Retrieve"), "retrieve", this); - // TRANSLATORS: storage button - mInvCloseButton = new Button(this, _("Close"), "close", this); - - mSlotsBarCell = &place(0, 0, mSlotsBar, 6); - mSortDropDownCell = &place(6, 0, mSortDropDown, 1); - - mFilterCell = &place(0, 1, mFilter, 7).setPadding(3); - mNameFilterCell = &place(6, 1, mNameFilter, 1); - - place(0, 2, invenScroll, 7, 4); - place(0, 6, mStoreButton); - place(1, 6, mRetrieveButton); - place(6, 6, mInvCloseButton); - } - - Layout &layout = getLayout(); - layout.setRowHeight(2, Layout::AUTO_SET); - - mInventory->addInventoyListener(this); - - invInstances.push_back(this); - - if (inventory && inventory->isMainInventory()) - { - updateDropButton(); - } - else - { - if (!invInstances.empty()) - invInstances.front()->updateDropButton(); - } - - loadWindowState(); - enableVisibleSound(true); - slotsChanged(mInventory); - - widgetResized(gcn::Event(nullptr)); - if (!isMainInventory()) - setVisible(true); -} - -InventoryWindow::~InventoryWindow() -{ - invInstances.remove(this); - mInventory->removeInventoyListener(this); - if (!invInstances.empty()) - invInstances.front()->updateDropButton(); - - mSortDropDown->hideDrop(false); - delete mSortModel; - mSortModel = nullptr; - mTextPopup = nullptr; -} - -void InventoryWindow::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "outfit") - { - if (outfitWindow) - { - outfitWindow->setVisible(!outfitWindow->isWindowVisible()); - if (outfitWindow->isWindowVisible()) - outfitWindow->requestMoveToTop(); - } - } - else if (eventId == "shop") - { - if (shopWindow) - { - shopWindow->setVisible(!shopWindow->isWindowVisible()); - if (shopWindow->isWindowVisible()) - shopWindow->requestMoveToTop(); - } - } - else if (eventId == "equipment") - { - if (equipmentWindow) - { - equipmentWindow->setVisible(!equipmentWindow->isWindowVisible()); - if (equipmentWindow->isWindowVisible()) - equipmentWindow->requestMoveToTop(); - } - } - else if (eventId == "close") - { - close(); - } - else if (eventId == "store") - { - if (!inventoryWindow || !inventoryWindow->isWindowVisible()) - return; - - Item *const item = inventoryWindow->getSelectedItem(); - - if (!item) - return; - - ItemAmountWindow::showWindow(ItemAmountWindow::StoreAdd, this, item); - } - else if (eventId == "sort") - { - mItems->setSortType(mSortDropDown->getSelected()); - return; - } - else if (eventId == "namefilter") - { - mItems->setName(mNameFilter->getText()); - mItems->updateMatrix(); - } - else if (!eventId.find("tag_")) - { - std::string tagName = event.getId().substr(4); - mItems->setFilter(ItemDB::getTagId(tagName)); - return; - } - - Item *const item = mItems->getSelectedItem(); - - if (!item) - return; - - if (eventId == "use") - { - if (item->isEquipment()) - { - if (item->isEquipped()) - Net::getInventoryHandler()->unequipItem(item); - else - Net::getInventoryHandler()->equipItem(item); - } - else - { - if (PlayerInfo::isItemProtected(item->getId())) - return; - Net::getInventoryHandler()->useItem(item); - } - } - if (eventId == "equip") - { - if (!item->isEquipment()) - { - if (item->isEquipped()) - Net::getInventoryHandler()->unequipItem(item); - else - Net::getInventoryHandler()->equipItem(item); - } - else - { - if (PlayerInfo::isItemProtected(item->getId())) - return; - Net::getInventoryHandler()->useItem(item); - } - } - else if (eventId == "drop") - { - if (PlayerInfo::isItemProtected(item->getId())) - return; - - if (isStorageActive()) - { - Net::getInventoryHandler()->moveItem2(Inventory::INVENTORY, - item->getInvIndex(), item->getQuantity(), - Inventory::STORAGE); - } - else - { - if (inputManager.isActionActive(static_cast(Input::KEY_MOD))) - { - Net::getInventoryHandler()->dropItem( - item, item->getQuantity()); - } - else - { - ItemAmountWindow::showWindow(ItemAmountWindow::ItemDrop, - this, item); - } - } - } - else if (eventId == "split") - { - ItemAmountWindow::showWindow(ItemAmountWindow::ItemSplit, this, item, - (item->getQuantity() - 1)); - } - else if (eventId == "retrieve") - { - ItemAmountWindow::showWindow(ItemAmountWindow::StoreRemove, - this, item); - } -} - -Item *InventoryWindow::getSelectedItem() const -{ - return mItems->getSelectedItem(); -} - -void InventoryWindow::unselectItem() -{ - mItems->selectNone(); -} - -void InventoryWindow::widgetHidden(const gcn::Event &event) -{ - Window::widgetHidden(event); - mItems->hidePopup(); -} - -void InventoryWindow::mouseClicked(gcn::MouseEvent &event) -{ - Window::mouseClicked(event); - - const int clicks = event.getClickCount(); - - if (clicks == 2 && gui) - gui->resetClickCount(); - - const bool mod = (isStorageActive() && inputManager.isActionActive( - static_cast(Input::KEY_MOD))); - - const bool mod2 = (tradeWindow && tradeWindow->isWindowVisible() - && inputManager.isActionActive(static_cast(Input::KEY_MOD))); - - if (!mod && !mod2 && event.getButton() == gcn::MouseEvent::RIGHT) - { - Item *const item = mItems->getSelectedItem(); - - if (!item) - return; - - /* Convert relative to the window coordinates to absolute screen - * coordinates. - */ - const int mx = event.getX() + getX(); - const int my = event.getY() + getY(); - - if (viewport) - viewport->showPopup(this, mx, my, item, isMainInventory()); - } - - if (!mInventory) - return; - - if (event.getButton() == gcn::MouseEvent::LEFT - || event.getButton() == gcn::MouseEvent::RIGHT) - { - Item *const item = mItems->getSelectedItem(); - - if (!item) - return; - - if (mod) - { - if (mInventory->isMainInventory()) - { - if (event.getButton() == gcn::MouseEvent::RIGHT) - { - ItemAmountWindow::showWindow(ItemAmountWindow::StoreAdd, - inventoryWindow, item); - } - else - { - Net::getInventoryHandler()->moveItem2(Inventory::INVENTORY, - item->getInvIndex(), item->getQuantity(), - Inventory::STORAGE); - } - } - else - { - if (event.getButton() == gcn::MouseEvent::RIGHT) - { - ItemAmountWindow::showWindow(ItemAmountWindow::StoreRemove, - inventoryWindow, item); - } - else - { - Net::getInventoryHandler()->moveItem2(Inventory::STORAGE, - item->getInvIndex(), item->getQuantity(), - Inventory::INVENTORY); - } - } - } - else if (mod2 && mInventory->isMainInventory()) - { - if (PlayerInfo::isItemProtected(item->getId())) - return; - if (event.getButton() == gcn::MouseEvent::RIGHT) - { - ItemAmountWindow::showWindow(ItemAmountWindow::TradeAdd, - tradeWindow, item); - } - else - { - if (tradeWindow) - tradeWindow->tradeItem(item, item->getQuantity(), true); - } - } - else if (clicks == 2) - { - if (mInventory->isMainInventory()) - { - if (isStorageActive()) - { - ItemAmountWindow::showWindow(ItemAmountWindow::StoreAdd, - inventoryWindow, item); - } - else if (tradeWindow && tradeWindow->isWindowVisible()) - { - if (PlayerInfo::isItemProtected(item->getId())) - return; - ItemAmountWindow::showWindow(ItemAmountWindow::TradeAdd, - tradeWindow, item); - } - else - { - if (item->isEquipment()) - { - if (item->isEquipped()) - Net::getInventoryHandler()->unequipItem(item); - else - Net::getInventoryHandler()->equipItem(item); - } - else - { - if (PlayerInfo::isItemProtected(item->getId())) - return; - Net::getInventoryHandler()->useItem(item); - } - } - } - else - { - if (isStorageActive()) - { - ItemAmountWindow::showWindow(ItemAmountWindow::StoreRemove, - inventoryWindow, item); - } - } - } - } -} - -void InventoryWindow::mouseMoved(gcn::MouseEvent &event) -{ - Window::mouseMoved(event); - const gcn::Widget *const src = event.getSource(); - if (src == mSlotsBar || src == mWeightBar) - { - const int x = event.getX(); - const int y = event.getY(); - const gcn::Rectangle &rect = mDimension; - mTextPopup->show(rect.x + x, rect.y + y, strprintf(_("Money: %s"), - Units::formatCurrency(PlayerInfo::getAttribute( - PlayerInfo::MONEY)).c_str())); - } - else - { - mTextPopup->hide(); - } -} - -void InventoryWindow::mouseExited(gcn::MouseEvent &event A_UNUSED) -{ - mTextPopup->hide(); -} - -void InventoryWindow::keyPressed(gcn::KeyEvent &event) -{ - if (static_cast(&event)->getActionId() - == static_cast(Input::KEY_GUI_MOD)) - { - mSplit = true; - } -} - -void InventoryWindow::keyReleased(gcn::KeyEvent &event) -{ - if (static_cast(&event)->getActionId() - == static_cast(Input::KEY_GUI_MOD)) - { - mSplit = false; - } -} - -void InventoryWindow::valueChanged(const gcn::SelectionEvent &event A_UNUSED) -{ - if (!mInventory || !mInventory->isMainInventory()) - return; - - Item *const item = mItems->getSelectedItem(); - - if (mSplit && item && Net::getInventoryHandler()-> - canSplit(mItems->getSelectedItem())) - { - ItemAmountWindow::showWindow(ItemAmountWindow::ItemSplit, - this, item, item->getQuantity() - 1); - } - updateButtons(item); -} - -void InventoryWindow::updateButtons(const Item *item) -{ - if (!mInventory || !mInventory->isMainInventory()) - return; - - const Item *const selectedItem = mItems->getSelectedItem(); - if (item && selectedItem != item) - return; - - if (!item) - item = selectedItem; - - if (!item || item->getQuantity() == 0) - { - if (mUseButton) - mUseButton->setEnabled(true); - if (mDropButton) - mDropButton->setEnabled(true); - return; - } - - if (mUseButton) - mUseButton->setEnabled(true); - if (mDropButton) - mDropButton->setEnabled(true); - - if (mUseButton) - { - if (item->isEquipment()) - { - if (item->isEquipped()) - { - // TRANSLATORS: inventory button - mUseButton->setCaption(_("Unequip")); - } - else - { - // TRANSLATORS: inventory button - mUseButton->setCaption(_("Equip")); - } - } - else - { - // TRANSLATORS: inventory button - mUseButton->setCaption(_("Use")); - } - } - - updateDropButton(); - - if (mSplitButton) - { - if (Net::getInventoryHandler()->canSplit(item)) - mSplitButton->setEnabled(true); - else - mSplitButton->setEnabled(false); - } -} - -void InventoryWindow::setSplitAllowed(const bool allowed) -{ - mSplitButton->setVisible(allowed); -} - -void InventoryWindow::close() -{ - if (this == inventoryWindow) - { - setVisible(false); - } - else - { - if (Net::getInventoryHandler()) - Net::getInventoryHandler()->closeStorage(Inventory::STORAGE); - scheduleDelete(); - } -} - -void InventoryWindow::processEvent(const Channels channel A_UNUSED, - const DepricatedEvent &event) -{ - if (event.getName() == EVENT_UPDATEATTRIBUTE) - { - const int id = event.getInt("id"); - if (id == PlayerInfo::TOTAL_WEIGHT || id == PlayerInfo::MAX_WEIGHT) - updateWeight(); - } -} - -void InventoryWindow::updateWeight() -{ - if (!isMainInventory()) - return; - - const int total = PlayerInfo::getAttribute(PlayerInfo::TOTAL_WEIGHT); - const int max = PlayerInfo::getAttribute(PlayerInfo::MAX_WEIGHT); - - if (max <= 0) - return; - - // Adjust progress bar - mWeightBar->setProgress(static_cast(total) - / static_cast(max)); - mWeightBar->setText(strprintf("%s/%s", Units::formatWeight(total).c_str(), - Units::formatWeight(max).c_str())); -} - -void InventoryWindow::slotsChanged(Inventory *const inventory) -{ - if (inventory == mInventory) - { - const int usedSlots = mInventory->getNumberOfSlotsUsed(); - const int maxSlots = mInventory->getSize(); - - if (maxSlots) - { - mSlotsBar->setProgress(static_cast(usedSlots) - / static_cast(maxSlots)); - } - - mSlotsBar->setText(strprintf("%d/%d", usedSlots, maxSlots)); - mItems->updateMatrix(); - } -} - -void InventoryWindow::updateDropButton() -{ - if (!mDropButton) - return; - - if (isStorageActive()) - { - // TRANSLATORS: inventory button - mDropButton->setCaption(_("Store")); - } - else - { - const Item *const item = mItems->getSelectedItem(); - if (item && item->getQuantity() > 1) - { - // TRANSLATORS: inventory button - mDropButton->setCaption(_("Drop...")); - } - else - { - // TRANSLATORS: inventory button - mDropButton->setCaption(_("Drop")); - } - } -} - -bool InventoryWindow::isInputFocused() const -{ - return mNameFilter && mNameFilter->isFocused(); -} - -bool InventoryWindow::isAnyInputFocused() -{ - FOR_EACH (WindowList::const_iterator, it, invInstances) - { - if ((*it) && (*it)->isInputFocused()) - return true; - } - return false; -} - -void InventoryWindow::widgetResized(const gcn::Event &event) -{ - Window::widgetResized(event); - - if (!isMainInventory()) - return; - - if (getWidth() < 600) - { - if (!mCompactMode) - { - mNameFilter->setVisible(false); - mNameFilterCell->setType(LayoutCell::NONE); - mFilterCell->setWidth(mFilterCell->getWidth() + 2); - mCompactMode = true; - } - } - else if (mCompactMode) - { - mNameFilter->setVisible(true); - mNameFilterCell->setType(LayoutCell::WIDGET); - mFilterCell->setWidth(mFilterCell->getWidth() - 2); - mCompactMode = false; - } -} - -void InventoryWindow::setVisible(bool visible) -{ - if (!visible) - mSortDropDown->hideDrop(); - Window::setVisible(visible); -} diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h deleted file mode 100644 index 7bd4ce466..000000000 --- a/src/gui/inventorywindow.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_INVENTORYWINDOW_H -#define GUI_INVENTORYWINDOW_H - -#include "inventory.h" -#include "depricatedlistener.h" - -#include "gui/widgets/window.h" - -#include -#include -#include - -class Button; -class DropDown; -class Item; -class ItemContainer; -class Label; -class LayoutCell; -class ProgressBar; -class SortListModelInv; -class TabStrip; -class TextField; -class TextPopup; - -/** - * Inventory dialog. - * - * \ingroup Interface - */ -class InventoryWindow final : public Window, - public gcn::ActionListener, - public gcn::KeyListener, - public gcn::SelectionListener, - public InventoryListener, - public DepricatedListener -{ - public: - /** - * Constructor. - */ - explicit InventoryWindow(Inventory *const inventory); - - A_DELETE_COPY(InventoryWindow) - - /** - * Destructor. - */ - ~InventoryWindow(); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - /** - * Returns the selected item. - */ - Item* getSelectedItem() const A_WARN_UNUSED; - - /** - * Unselect item - */ - void unselectItem(); - - /** - * Handles closing of the window - */ - void widgetHidden(const gcn::Event &event) override; - - /** - * Handles the mouse clicks. - */ - void mouseClicked(gcn::MouseEvent &event) override; - - /** - * Handles the key presses. - */ - void keyPressed(gcn::KeyEvent &event) override; - - /** - * Handles the key releases. - */ - void keyReleased(gcn::KeyEvent &event) override; - - /** - * Updates labels to currently selected item. - */ - void valueChanged(const gcn::SelectionEvent &event) override; - - /** - * Sets whether the split button should be shown. - */ - void setSplitAllowed(const bool allowed); - - /** - * Closes the Storage Window, as well as telling the server that the - * window has been closed. - */ - void close(); - - void slotsChanged(Inventory *const inventory); - - bool isMainInventory() const A_WARN_UNUSED - { return mInventory->isMainInventory(); } - - /** - * Returns true if any instances exist. - */ - static bool isStorageActive() A_WARN_UNUSED - { return invInstances.size() > 1; } - - void updateDropButton(); - - void processEvent(const Channels channel, - const DepricatedEvent &event) override; - - void updateButtons(const Item *item = nullptr); - - bool isInputFocused() const A_WARN_UNUSED; - - void widgetResized(const gcn::Event &event) override; - - void mouseMoved(gcn::MouseEvent &event) override; - - void mouseExited(gcn::MouseEvent &event) override; - - void setVisible(bool visible) override; - - static bool isAnyInputFocused(); - - private: - /** - * Updates the weight bar. - */ - void updateWeight(); - - typedef std::list WindowList; - static WindowList invInstances; - - Inventory *mInventory; - ItemContainer *mItems; - - std::string mWeight; - std::string mSlots; - - Button *mUseButton; - Button *mDropButton; - Button *mSplitButton; - Button *mOutfitButton; - Button *mShopButton; - Button *mEquipmentButton; - Button *mStoreButton; - Button *mRetrieveButton; - Button *mInvCloseButton; - - ProgressBar *mWeightBar; - ProgressBar *mSlotsBar; - TabStrip *mFilter; - SortListModelInv *mSortModel; - DropDown *mSortDropDown; - TextField *mNameFilter; - LayoutCell *mSortDropDownCell; - LayoutCell *mNameFilterCell; - LayoutCell *mFilterCell; - LayoutCell *mSlotsBarCell; - TextPopup *mTextPopup; - - bool mSplit; - bool mCompactMode; -}; - -extern InventoryWindow *inventoryWindow; - -#endif // GUI_INVENTORYWINDOW_H diff --git a/src/gui/itemamountwindow.cpp b/src/gui/itemamountwindow.cpp deleted file mode 100644 index 1fd15e351..000000000 --- a/src/gui/itemamountwindow.cpp +++ /dev/null @@ -1,450 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/itemamountwindow.h" - -#include "inventory.h" -#include "item.h" - -#include "input/keyboardconfig.h" - -#include "gui/tradewindow.h" -#include "net/inventoryhandler.h" -#include "gui/itempopup.h" -#include "net/net.h" -#include "gui/shopwindow.h" -#include "gui/viewport.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/dropdown.h" -#include "gui/widgets/icon.h" -#include "gui/widgets/inttextfield.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/label.h" -#include "gui/widgets/slider.h" - -#include "utils/gettext.h" - -#include - -#include "debug.h" - -class ItemsModal final : public gcn::ListModel -{ -public: - ItemsModal() : - mStrings() - { - const std::map &items = ItemDB::getItemInfos(); - std::list tempStrings; - - for (std::map::const_iterator - i = items.begin(), i_end = items.end(); - i != i_end; ++i) - { - if (i->first < 0) - continue; - - const ItemInfo &info = *i->second; - const std::string name = info.getName(); - if (name != "unnamed" && !info.getName().empty() - && info.getName() != "unnamed") - { - tempStrings.push_back(name); - } - } - tempStrings.sort(); - FOR_EACH (std::list::const_iterator, i, tempStrings) - mStrings.push_back(*i); - } - - A_DELETE_COPY(ItemsModal) - - ~ItemsModal() - { } - - int getNumberOfElements() override - { - return static_cast(mStrings.size()); - } - - std::string getElementAt(int i) override - { - if (i < 0 || i >= getNumberOfElements()) - return "???"; - return mStrings.at(i); - } -private: - StringVect mStrings; -}; - -void ItemAmountWindow::finish(Item *const item, const int amount, - const int price, const Usage usage) -{ - switch (usage) - { - case TradeAdd: - if (tradeWindow) - tradeWindow->tradeItem(item, amount); - break; - case ItemDrop: - Net::getInventoryHandler()->dropItem(item, amount); - break; - case ItemSplit: - Net::getInventoryHandler()->splitItem(item, amount); - break; - case StoreAdd: - Net::getInventoryHandler()->moveItem2(Inventory::INVENTORY, - item->getInvIndex(), amount, Inventory::STORAGE); - break; - case StoreRemove: - Net::getInventoryHandler()->moveItem2(Inventory::STORAGE, - item->getInvIndex(), amount, Inventory::INVENTORY); - break; - case ShopBuyAdd: - if (shopWindow) - shopWindow->addBuyItem(item, amount, price); - break; - case ShopSellAdd: - if (shopWindow) - shopWindow->addSellItem(item, amount, price); - break; - default: - break; - } -} - -ItemAmountWindow::ItemAmountWindow(const Usage usage, Window *const parent, - Item *const item, const int maxRange) : - Window("", false, parent, "amount.xml"), - gcn::ActionListener(), - gcn::KeyListener(), - mItemAmountTextField(new IntTextField(this, 1)), - mItemPriceTextField(nullptr), - mGPLabel(nullptr), - mItem(item), - mItemIcon(new Icon(this, item ? item->getImage() : nullptr)), - mMax(maxRange), - mUsage(usage), - mItemPopup(new ItemPopup), - mItemAmountSlide(new Slider(1.0, mMax)), - mItemPriceSlide(nullptr), - mItemDropDown(nullptr), - mItemsModal(nullptr), - mPrice(0), - mEnabledKeyboard(keyboard.isEnabled()) -{ - if (!mItem) - { - setVisible(false); - return; - } - if (usage == ShopBuyAdd) - mMax = 10000; - else if (!mMax) - mMax = mItem->getQuantity(); - - keyboard.setEnabled(false); - - mItemAmountTextField->setRange(1, mMax); - mItemAmountTextField->setWidth(35); - mItemAmountTextField->addKeyListener(this); - - mItemAmountSlide->setHeight(10); - mItemAmountSlide->setActionEventId("slide"); - mItemAmountSlide->addActionListener(this); - - if (mUsage == ShopBuyAdd || mUsage == ShopSellAdd) - { - mItemPriceTextField = new IntTextField(this, 1); - mItemPriceTextField->setRange(1, 10000000); - mItemPriceTextField->setWidth(35); - mItemPriceTextField->addKeyListener(this); - - mItemPriceSlide = new Slider(1.0, 10000000); - mItemPriceSlide->setHeight(10); - mItemPriceSlide->setActionEventId("slidePrice"); - mItemPriceSlide->addActionListener(this); - - mGPLabel = new Label(this, " GP"); - } - - if (mUsage == ShopBuyAdd) - { - mItemsModal = new ItemsModal; - mItemDropDown = new DropDown(this, mItemsModal); - mItemDropDown->setActionEventId("itemType"); - mItemDropDown->addActionListener(this); - } - - // Buttons - // TRANSLATORS: item amount window button - Button *const minusAmountButton = new Button(this, _("-"), "dec", this); - // TRANSLATORS: item amount window button - Button *const plusAmountButton = new Button(this, _("+"), "inc", this); - // TRANSLATORS: item amount window button - Button *const okButton = new Button(this, _("OK"), "ok", this); - // TRANSLATORS: item amount window button - Button *const cancelButton = new Button(this, _("Cancel"), "cancel", this); - // TRANSLATORS: item amount window button - Button *const addAllButton = new Button(this, _("All"), "all", this); - - minusAmountButton->adjustSize(); - minusAmountButton->setWidth(plusAmountButton->getWidth()); - - // Set positions - ContainerPlacer placer; - placer = getPlacer(0, 0); - int n = 0; - if (mUsage == ShopBuyAdd) - { - placer(0, n, mItemDropDown, 8); - n++; - } - placer(1, n, minusAmountButton); - placer(2, n, mItemAmountTextField, 3); - placer(5, n, plusAmountButton); - placer(6, n, addAllButton); - - placer(0, n, mItemIcon, 1, 3); - placer(1, n + 1, mItemAmountSlide, 7); - - if (mUsage == ShopBuyAdd || mUsage == ShopSellAdd) - { - Button *const minusPriceButton = new Button( - // TRANSLATORS: item amount window button - this, _("-"), "decPrice", this); - Button *const plusPriceButton = new Button( - // TRANSLATORS: item amount window button - this, _("+"), "incPrice", this); - minusPriceButton->adjustSize(); - minusPriceButton->setWidth(plusPriceButton->getWidth()); - - placer(1, n + 2, minusPriceButton); - placer(2, n + 2, mItemPriceTextField, 3); - placer(5, n + 2, plusPriceButton); - placer(6, n + 2, mGPLabel); - - placer(1, n + 3, mItemPriceSlide, 7); - placer(4, n + 5, cancelButton); - placer(5, n + 5, okButton); - } - else - { - placer(4, n + 2, cancelButton); - placer(5, n + 2, okButton); - } - - reflowLayout(225, 0); - - resetAmount(); - - switch (usage) - { - case TradeAdd: - // TRANSLATORS: amount window message - setCaption(_("Select amount of items to trade.")); - break; - case ItemDrop: - // TRANSLATORS: amount window message - setCaption(_("Select amount of items to drop.")); - break; - case StoreAdd: - // TRANSLATORS: amount window message - setCaption(_("Select amount of items to store.")); - break; - case StoreRemove: - // TRANSLATORS: amount window message - setCaption(_("Select amount of items to retrieve.")); - break; - case ItemSplit: - // TRANSLATORS: amount window message - setCaption(_("Select amount of items to split.")); - break; - case ShopBuyAdd: - // TRANSLATORS: amount window message - setCaption(_("Add to buy shop.")); - break; - case ShopSellAdd: - // TRANSLATORS: amount window message - setCaption(_("Add to sell shop.")); - break; - default: - // TRANSLATORS: amount window message - setCaption(_("Unknown.")); - break; - } - - setLocationRelativeTo(getParentWindow()); - setVisible(true); - - mItemIcon->addMouseListener(this); -} - -ItemAmountWindow::~ItemAmountWindow() -{ - delete mItemPopup; - mItemPopup = nullptr; -} - -// Show ItemTooltip -void ItemAmountWindow::mouseMoved(gcn::MouseEvent &event) -{ - Window::mouseMoved(event); - - if (!viewport || !mItemPopup) - return; - - if (event.getSource() == mItemIcon) - { - mItemPopup->setItem(mItem); - mItemPopup->position(viewport->getMouseX(), viewport->getMouseY()); - } -} - -// Hide ItemTooltip -void ItemAmountWindow::mouseExited(gcn::MouseEvent &event A_UNUSED) -{ - if (mItemPopup) - mItemPopup->setVisible(false); -} - -void ItemAmountWindow::resetAmount() -{ - mItemAmountTextField->setValue(1); -} - -void ItemAmountWindow::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "cancel") - { - close(); - return; - } - else if (eventId == "ok") - { - if (mItemPriceTextField) - { - finish(mItem, mItemAmountTextField->getValue(), - mItemPriceTextField->getValue(), mUsage); - } - else - { - finish(mItem, mItemAmountTextField->getValue(), - 0, mUsage); - } - close(); - return; - } - else if (eventId == "itemType") - { - if (!mItemDropDown || !mItemsModal) - return; - - const int id = ItemDB::get(mItemsModal->getElementAt( - mItemDropDown->getSelected())).getId(); - - mItem = new Item(id, 10000); - - if (mUsage == ShopBuyAdd) - mMax = 10000; - else if (!mMax) - mMax = mItem->getQuantity(); - - mItemIcon->setImage(mItem->getImage()); - } - - int amount = mItemAmountTextField->getValue(); - - if (eventId == "inc" && amount < mMax) - amount++; - else if (eventId == "dec" && amount > 1) - amount--; - else if (eventId == "all") - amount = mMax; - else if (eventId == "slide") - amount = static_cast(mItemAmountSlide->getValue()); - mItemAmountTextField->setValue(amount); - mItemAmountSlide->setValue(amount); - - if (mItemPriceTextField && mItemPriceSlide) - { - if (mPrice > 7) - mPrice = 7; - else if (mPrice < 0) - mPrice = 0; - - int price = 0; - - if (eventId == "incPrice") - { - mPrice++; - price = static_cast(pow(10.0, mPrice)); - mItemPriceTextField->setValue(price); - mItemPriceSlide->setValue(price); - } - else if (eventId == "decPrice") - { - mPrice--; - price = static_cast(pow(10.0, mPrice)); - mItemPriceTextField->setValue(price); - mItemPriceSlide->setValue(price); - } - else if (eventId == "slidePrice") - { - price = static_cast(mItemPriceSlide->getValue()); - if (price) - mPrice = static_cast(log(static_cast(price))); - else - mPrice = 0; - mItemPriceTextField->setValue(price); - mItemPriceSlide->setValue(price); - } - } -} - -void ItemAmountWindow::close() -{ - keyboard.setEnabled(mEnabledKeyboard); - scheduleDelete(); -} - -void ItemAmountWindow::keyReleased(gcn::KeyEvent &keyEvent A_UNUSED) -{ - mItemAmountSlide->setValue(mItemAmountTextField->getValue()); -} - -void ItemAmountWindow::showWindow(const Usage usage, Window *const parent, - Item *const item, int maxRange) -{ - if (!item) - return; - - if (!maxRange) - maxRange = item->getQuantity(); - - if (usage != ShopBuyAdd && usage != ShopSellAdd && maxRange <= 1) - finish(item, maxRange, 0, usage); - else - new ItemAmountWindow(usage, parent, item, maxRange); -} diff --git a/src/gui/itemamountwindow.h b/src/gui/itemamountwindow.h deleted file mode 100644 index 1c95980fb..000000000 --- a/src/gui/itemamountwindow.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_ITEMAMOUNTWINDOW_H -#define GUI_ITEMAMOUNTWINDOW_H - -#include "gui/widgets/window.h" - -#include -#include - -class DropDown; -class Icon; -class IntTextField; -class Item; -class ItemsModal; -class ItemPopup; -class Label; -class Slider; - -/** - * Window used for selecting the amount of items to drop, trade or split. - * - * \ingroup Interface - */ -class ItemAmountWindow final : public Window, - public gcn::ActionListener, - public gcn::KeyListener -{ - public: - enum Usage - { - TradeAdd = 0, - ItemDrop, - StoreAdd, - StoreRemove, - ItemSplit, - ShopBuyAdd, - ShopSellAdd - }; - - A_DELETE_COPY(ItemAmountWindow) - - /** - * Called when receiving actions from widget. - */ - void action(const gcn::ActionEvent &event) override; - - /** - * Sets default amount value. - */ - void resetAmount(); - - // MouseListener - void mouseMoved(gcn::MouseEvent &event) override; - - void mouseExited(gcn::MouseEvent &event) override; - - /** - * Schedules the Item Amount window for deletion. - */ - void close(); - - void keyReleased(gcn::KeyEvent &keyEvent) override; - - /** - * Creates the dialog, or bypass it if there aren't enough items. - */ - static void showWindow(const Usage usage, Window *const parent, - Item *const item, int maxRange = 0); - - ~ItemAmountWindow(); - - private: - static void finish(Item *const item, const int amount, - const int price, const Usage usage); - - ItemAmountWindow(const Usage usage, Window *const parent, - Item *const item, const int maxRange = 0); - - IntTextField *mItemAmountTextField; /**< Item amount caption. */ - IntTextField *mItemPriceTextField; /**< Item price caption. */ - Label *mGPLabel; - Item *mItem; - Icon *mItemIcon; - - int mMax; - Usage mUsage; - ItemPopup *mItemPopup; - - /** - * Item Amount buttons. - */ - Slider *mItemAmountSlide; - - Slider *mItemPriceSlide; - - DropDown *mItemDropDown; - - ItemsModal *mItemsModal; - - int mPrice; - - bool mEnabledKeyboard; -}; - -#endif // GUI_ITEMAMOUNTWINDOW_H diff --git a/src/gui/killstats.cpp b/src/gui/killstats.cpp deleted file mode 100644 index d289c1e27..000000000 --- a/src/gui/killstats.cpp +++ /dev/null @@ -1,520 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 Andrei Karas - * Copyright (C) 2011-2013 The ManaPlus developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/killstats.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/label.h" -#include "gui/widgets/layout.h" - -#include "actorspritemanager.h" -#include "game.h" - -#include "being/localplayer.h" -#include "being/playerinfo.h" - -#include "utils/gettext.h" -#include "utils/stringutils.h" - -#include "debug.h" - -KillStats::KillStats() : - // TRANSLATORS: kill stats window name - Window(_("Kill stats"), false, nullptr, "killstats.xml"), - gcn::ActionListener(), - mKillCounter(0), - mExpCounter(0), - mKillTCounter(0), - mExpTCounter(0), - mKillTimer(0), - // TRANSLATORS: kill stats window button - mResetButton(new Button(this, _("Reset stats"), "reset", this)), - // TRANSLATORS: kill stats window button - mTimerButton(new Button(this, _("Reset timer"), "timer", this)), - mLine1(nullptr), - mLine2(nullptr), - mLine3(nullptr), - // TRANSLATORS: kill stats window label - mLine4(new Label(this, strprintf(_("Kills: %s, total exp: %s"), - "?", "?"))), - // TRANSLATORS: kill stats window label - mLine5(new Label(this, strprintf(_("Avg Exp: %s"), "?"))), - // TRANSLATORS: kill stats window label - mLine6(new Label(this, strprintf(_("No. of avg mob to next level: %s"), - "?"))), - // TRANSLATORS: kill stats window label - mLine7(new Label(this, strprintf(_("Kills/Min: %s, Exp/Min: %s"), - "?", "?"))), - mExpSpeed1Label(new Label(this, strprintf(ngettext( - // TRANSLATORS: kill stats window label - "Exp speed per %d min: %s", "Exp speed per %d min: %s", 1), 1, "?"))), - mExpTime1Label(new Label(this, strprintf(ngettext( - "Time for next level per %d min: %s", - "Time for next level per %d min: %s", 1), 1, "?"))), - mExpSpeed5Label(new Label(this, strprintf(ngettext( - "Exp speed per %d min: %s", "Exp speed per %d min: %s", 5), 5, "?"))), - mExpTime5Label(new Label(this, strprintf(ngettext( - "Time for next level per %d min: %s", - "Time for next level per %d min: %s", 5), 5, "?"))), - mExpSpeed15Label(new Label(this, strprintf(ngettext( - "Exp speed per %d min: %s", "Exp speed per %d min: %s", 15), - 15, "?"))), - mExpTime15Label(new Label(this, strprintf(ngettext( - "Time for next level per %d min: %s", - "Time for next level per %d min: %s", 15), 15, "?"))), - // TRANSLATORS: kill stats window label - mLastKillExpLabel(new Label(this, strprintf("%s ?", _("Last kill exp:")))), - mTimeBeforeJackoLabel(new Label(this, strprintf( - // TRANSLATORS: kill stats window label - "%s ?", _("Time before jacko spawn:")))), - m1minExpTime(0), - m1minExpNum(0), - m1minSpeed(0), - m5minExpTime(0), - m5minExpNum(0), - m5minSpeed(0), - m15minExpTime(0), - m15minExpNum(0), - m15minSpeed(0), - mJackoSpawnTime(0), - mJackoId(0), - mIsJackoAlive(false), - mIsJackoMustSpawn(true), - mIsJackoSpawnTimeUnknown(true) -{ - setWindowName("Kill stats"); - setCloseButton(true); - setResizable(true); - setSaveVisible(true); - setStickyButtonLock(true); - setDefaultSize(250, 250, 350, 300); - - listen(CHANNEL_ATTRIBUTES); - const int xp(PlayerInfo::getAttribute(PlayerInfo::EXP)); - int xpNextLevel(PlayerInfo::getAttribute(PlayerInfo::EXP_NEEDED)); - - if (!xpNextLevel) - xpNextLevel = 1; - - // TRANSLATORS: kill stats window label - mLine1 = new Label(this, strprintf(_("Level: %d at %f%%"), - player_node->getLevel(), static_cast(xp) - / static_cast(xpNextLevel) * 100.0)); - - // TRANSLATORS: kill stats window label - mLine2 = new Label(this, strprintf(_("Exp: %d/%d Left: %d"), - xp, xpNextLevel, xpNextLevel - xp)); - - // TRANSLATORS: kill stats window label - mLine3 = new Label(this, strprintf(_("1%% = %d exp, avg mob for 1%%: %s"), - xpNextLevel / 100, "?")); - - place(0, 0, mLine1, 6).setPadding(0); - place(0, 1, mLine2, 6).setPadding(0); - place(0, 2, mLine3, 6).setPadding(0); - place(0, 3, mLine4, 6).setPadding(0); - place(0, 4, mLine5, 6).setPadding(0); - place(0, 5, mLine6, 6).setPadding(0); - place(0, 6, mLine7, 6).setPadding(0); - - place(0, 7, mLastKillExpLabel, 6).setPadding(0); - place(0, 8, mTimeBeforeJackoLabel, 6).setPadding(0); - place(0, 9, mExpSpeed1Label, 6).setPadding(0); - place(0, 10, mExpTime1Label, 6).setPadding(0); - place(0, 11, mExpSpeed5Label, 6).setPadding(0); - place(0, 12, mExpTime5Label, 6).setPadding(0); - place(0, 13, mExpSpeed15Label, 6).setPadding(0); - place(0, 14, mExpTime15Label, 6).setPadding(0); - - place(5, 13, mTimerButton).setPadding(0); - place(5, 14, mResetButton).setPadding(0); - - loadWindowState(); - enableVisibleSound(true); -} - -KillStats::~KillStats() -{ -} - -void KillStats::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "reset") - { - mKillCounter = 0; - mExpCounter = 0; - mLine3->setCaption(strprintf("1%% = %d exp, avg mob for 1%%: %s", - PlayerInfo::getAttribute(PlayerInfo::EXP_NEEDED) / 100, "?")); - // TRANSLATORS: kill stats window label - mLine4->setCaption(strprintf(_("Kills: %s, total exp: %s"), "?", "?")); - // TRANSLATORS: kill stats window label - mLine5->setCaption(strprintf(_("Avg Exp: %s"), "?")); - mLine6->setCaption(strprintf( - // TRANSLATORS: kill stats window label - _("No. of avg mob to next level: %s"), "?")); - - resetTimes(); - } - else if (eventId == "timer") - { - mKillTimer = 0; - mKillTCounter = 0; - mExpTCounter = 0; - mLine7->setCaption(strprintf( - // TRANSLATORS: kill stats window label - _("Kills/Min: %s, Exp/Min: %s"), "?", "?")); - - resetTimes(); - } -} - -void KillStats::resetTimes() -{ - m1minExpTime = 0; - m1minExpNum = 0; - m1minSpeed = 0; - m5minExpTime = 0; - m5minExpNum = 0; - m5minSpeed = 0; - m15minExpTime = 0; - m15minExpNum = 0; - m15minSpeed = 0; -} - -void KillStats::gainXp(int xp) -{ - const int expNeed = PlayerInfo::getAttribute(PlayerInfo::EXP_NEEDED); - if (xp == expNeed) - xp = 0; - else if (!xp) - return; - - mKillCounter++; - mKillTCounter++; - - mExpCounter = mExpCounter + xp; - mExpTCounter = mExpTCounter + xp; - if (!mKillCounter) - mKillCounter = 1; - - const float AvgExp = static_cast(mExpCounter / mKillCounter); - int xpNextLevel(expNeed); - - if (mKillTimer == 0) - mKillTimer = cur_time; - - if (!xpNextLevel) - xpNextLevel = 1; - - double timeDiff = difftime(cur_time, mKillTimer) / 60; - - if (timeDiff <= 0.001) - timeDiff = 1; - - const int exp = PlayerInfo::getAttribute(PlayerInfo::EXP); - // TRANSLATORS: kill stats window label - mLine1->setCaption(strprintf(_("Level: %d at %f%%"), - player_node->getLevel(), static_cast(exp) - / static_cast(xpNextLevel) * 100.0)); - - // TRANSLATORS: kill stats window label - mLine2->setCaption(strprintf(_("Exp: %d/%d Left: %d"), exp, - xpNextLevel, xpNextLevel - exp)); - - if (AvgExp >= 0.001F && AvgExp <= 0.001F) - { - // TRANSLATORS: kill stats window label - mLine3->setCaption(strprintf(_("1%% = %d exp, avg mob for 1%%: %s"), - xpNextLevel / 100, "?")); - - // TRANSLATORS: kill stats window label - mLine5->setCaption(strprintf(_("Avg Exp: %s"), - toString(AvgExp).c_str())); - - mLine6->setCaption(strprintf( - // TRANSLATORS: kill stats window label - _("No. of avg mob to next level: %s"), "?")); - } - else - { - // TRANSLATORS: kill stats window label - mLine3->setCaption(strprintf(_("1%% = %d exp, avg mob for 1%%: %s"), - xpNextLevel / 100, toString((static_cast( - xpNextLevel) / 100) / AvgExp).c_str())); - - // TRANSLATORS: kill stats window label - mLine5->setCaption(strprintf(_("Avg Exp: %s"), - toString(AvgExp).c_str())); - - // TRANSLATORS: kill stats window label - mLine6->setCaption(strprintf(_("No. of avg mob to next level: %s"), - toString(static_cast(xpNextLevel - exp) / AvgExp).c_str())); - } - // TRANSLATORS: kill stats window label - mLine4->setCaption(strprintf(_("Kills: %s, total exp: %s"), - toString(mKillCounter).c_str(), toString(mExpCounter).c_str())); - - // TRANSLATORS: kill stats window label - mLine7->setCaption(strprintf(_("Kills/Min: %s, Exp/Min: %s"), - toString(mKillTCounter / timeDiff).c_str(), - toString(mExpTCounter / timeDiff).c_str())); - - // TRANSLATORS: kill stats window label - mLastKillExpLabel->setCaption(strprintf("%s %d", _("Last kill exp:"), xp)); - - recalcStats(); - update(); -} - -void KillStats::recalcStats() -{ - BLOCK_START("KillStats::recalcStats") - const int curTime = cur_time; - - // Need Update Exp Counter - if (curTime - m1minExpTime > 60) - { - const int newExp = PlayerInfo::getAttribute(PlayerInfo::EXP); - if (m1minExpTime != 0) - m1minSpeed = newExp - m1minExpNum; - else - m1minSpeed = 0; - m1minExpTime = curTime; - m1minExpNum = newExp; - } - - if (curTime - m5minExpTime > 60*5) - { - const int newExp = PlayerInfo::getAttribute(PlayerInfo::EXP); - if (m5minExpTime != 0) - m5minSpeed = newExp - m5minExpNum; - else - m5minSpeed = 0; - m5minExpTime = curTime; - m5minExpNum = newExp; - } - - if (curTime - m15minExpTime > 60*15) - { - const int newExp = PlayerInfo::getAttribute(PlayerInfo::EXP); - if (m15minExpTime != 0) - m15minSpeed = newExp - m15minExpNum; - else - m15minSpeed = 0; - m15minExpTime = curTime; - m15minExpNum = newExp; - } - validateJacko(); - BLOCK_END("KillStats::recalcStats") -} - -void KillStats::update() -{ - BLOCK_START("KillStats::update") - - mExpSpeed1Label->setCaption(strprintf(ngettext("Exp speed per %d min: %s", - "Exp speed per %d min: %s", 1), 1, toString(m1minSpeed).c_str())); - - if (m1minSpeed != 0) - { - // TRANSLATORS: kill stats window label - mExpTime1Label->setCaption(strprintf(_(" Time for next level: %s"), - toString(static_cast((PlayerInfo::getAttribute( - PlayerInfo::EXP_NEEDED) - PlayerInfo::getAttribute( - PlayerInfo::EXP)) / m1minSpeed)).c_str())); - } - else - { - mExpTime1Label->setCaption(strprintf( - // TRANSLATORS: kill stats window label - _(" Time for next level: %s"), "?")); - } - mExpTime1Label->adjustSize(); - - mExpSpeed5Label->setCaption(strprintf(ngettext("Exp speed per %d min: %s", - "Exp speed per %d min: %s", 5), 5, toString(m5minSpeed / 5).c_str())); - mExpSpeed5Label->adjustSize(); - - if (m5minSpeed != 0) - { - // TRANSLATORS: kill stats window label - mExpTime5Label->setCaption(strprintf(_(" Time for next level: %s"), - toString(static_cast((PlayerInfo::getAttribute( - PlayerInfo::EXP_NEEDED) - PlayerInfo::getAttribute( - PlayerInfo::EXP)) / m5minSpeed * 5)).c_str())); - } - else - { - mExpTime5Label->setCaption(strprintf( - // TRANSLATORS: kill stats window label - _(" Time for next level: %s"), "?")); - } - mExpTime5Label->adjustSize(); - - - mExpSpeed15Label->setCaption(strprintf(ngettext("Exp speed per %d min: %s", - "Exp speed per %d min: %s", 15), 15, toString( - m15minSpeed / 15).c_str())); - mExpSpeed15Label->adjustSize(); - - if (m15minSpeed != 0) - { - // TRANSLATORS: kill stats window label - mExpTime15Label->setCaption(strprintf(_(" Time for next level: %s"), - toString(static_cast((PlayerInfo::getAttribute( - PlayerInfo::EXP_NEEDED) - PlayerInfo::getAttribute( - PlayerInfo::EXP)) / m15minSpeed * 15)).c_str())); - } - else - { - mExpTime15Label->setCaption(strprintf( - // TRANSLATORS: kill stats window label - _(" Time for next level: %s"), "?")); - } - - validateJacko(); - updateJackoLabel(); - BLOCK_END("KillStats::update") -} - -void KillStats::updateJackoLabel() -{ - if (mIsJackoAlive) - { - mTimeBeforeJackoLabel->setCaption(strprintf("%s jacko alive", - // TRANSLATORS: kill stats window label - _("Time before jacko spawn:"))); - } - else if (mIsJackoSpawnTimeUnknown && mJackoSpawnTime != 0) - { - // TRANSLATORS: kill stats window label - mTimeBeforeJackoLabel->setCaption(strprintf( - // TRANSLATORS: kill stats window label - _("%s %d?"), _("Time before jacko spawn:"), - mJackoSpawnTime - cur_time)); - } - else if (mIsJackoMustSpawn) - { - mTimeBeforeJackoLabel->setCaption(strprintf("%s %s", - // TRANSLATORS: kill stats window label - _("Time before jacko spawn:"), _("jacko spawning"))); - } - else - { - mTimeBeforeJackoLabel->setCaption(strprintf("%s %d", - // TRANSLATORS: kill stats window label - _("Time before jacko spawn:"), mJackoSpawnTime - cur_time)); - } -} - -void KillStats::jackoDead(const int id) -{ - if (id == mJackoId && mIsJackoAlive) - { - mIsJackoAlive = false; - mJackoSpawnTime = cur_time + 60*4; - mIsJackoSpawnTimeUnknown = false; - updateJackoLabel(); - } -} - -void KillStats::jackoAlive(const int id) -{ - if (!mIsJackoAlive) - { - mJackoId = id; - mIsJackoAlive = true; - mIsJackoMustSpawn = false; - mJackoSpawnTime = 0; - mIsJackoSpawnTimeUnknown = false; - updateJackoLabel(); - } -} - -void KillStats::validateJacko() -{ - if (!actorSpriteManager || !player_node) - return; - - const Map *const currentMap = Game::instance()->getCurrentMap(); - if (currentMap) - { - if (currentMap->getProperty("_realfilename") == "018-1" - || currentMap->getProperty("_realfilename") == "maps/018-1.tmx") - { - if (player_node->getTileX() >= 167 - && player_node->getTileX() <= 175 - && player_node->getTileY() >= 21 - && player_node->getTileY() <= 46) - { - const Being *const dstBeing - = actorSpriteManager->findBeingByName( - "Jack O", Being::MONSTER); - if (mIsJackoAlive && !dstBeing) - { - mIsJackoAlive = false; - mJackoSpawnTime = cur_time + 60*4; - mIsJackoSpawnTimeUnknown = true; - } - } - } - - if (!mIsJackoAlive && cur_time > mJackoSpawnTime + 15) - mIsJackoMustSpawn = true; - } -} - -void KillStats::processEvent(const Channels channel A_UNUSED, - const DepricatedEvent &event) -{ - if (event.getName() == EVENT_UPDATEATTRIBUTE) - { - const int id = event.getInt("id"); - if (id == PlayerInfo::EXP || id == PlayerInfo::EXP_NEEDED) - { - gainXp(event.getInt("newValue") - event.getInt("oldValue")); - } - else if (id == PlayerInfo::LEVEL) - { - mKillCounter = 0; - mKillTCounter = 0; - mExpCounter = 0; - mExpTCounter = 0; - mLine3->setCaption(strprintf("1%% = %d exp, avg mob for 1%%: %s", - PlayerInfo::getAttribute(PlayerInfo::EXP_NEEDED) / 100, "?")); - mLine4->setCaption(strprintf( - // TRANSLATORS: kill stats window label - _("Kills: %s, total exp: %s"), "?", "?")); - // TRANSLATORS: kill stats window label - mLine5->setCaption(strprintf(_("Avg Exp: %s"), "?")); - mLine6->setCaption(strprintf( - // TRANSLATORS: kill stats window label - _("No. of avg mob to next level: %s"), "?")); - mLine7->setCaption(strprintf( - // TRANSLATORS: kill stats window label - _("Kills/Min: %s, Exp/Min: %s"), "?", "?")); - - resetTimes(); - } - } -} diff --git a/src/gui/killstats.h b/src/gui/killstats.h deleted file mode 100644 index a5b59affb..000000000 --- a/src/gui/killstats.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 Andrei Karas - * Copyright (C) 2011-2013 The ManaPlus developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_KILLSTATS_H -#define GUI_KILLSTATS_H - -#include - -#include "depricatedlistener.h" - -#include "gui/widgets/window.h" - -class Label; -class Button; - -class KillStats final : public Window, - private gcn::ActionListener, - public DepricatedListener -{ - public: - /** - * Constructor. - */ - KillStats(); - - A_DELETE_COPY(KillStats) - - /** - * Destructor. - */ - ~KillStats(); - - /** - * Stuff. - */ - void action(const gcn::ActionEvent &event) override; - - void gainXp(int Xp); - - /** - * Recalc stats if needed - */ - void recalcStats(); - - /** - * Updates this dialog - */ - void update(); - - /** - * Updates jacko info - */ - void updateJackoLabel(); - - void jackoDead(const int id); - - void jackoAlive(const int id); - - void processEvent(const Channels channel A_UNUSED, - const DepricatedEvent &event) override; - - void resetTimes(); - - private: - void validateJacko(); - - int mKillCounter; /**< Session Kill counter. */ - int mExpCounter; /**< Session Exp counter. */ - int mKillTCounter; /**< Timer Kill counter. */ - int mExpTCounter; /**< Timer Exp counter. */ - time_t mKillTimer; /**< Timer for kill stats. */ - Button *mResetButton; - Button *mTimerButton; - Label *mLine1; - Label *mLine2; - Label *mLine3; - Label *mLine4; - Label *mLine5; - Label *mLine6; - Label *mLine7; - - Label *mExpSpeed1Label; - Label *mExpTime1Label; - Label *mExpSpeed5Label; - Label *mExpTime5Label; - Label *mExpSpeed15Label; - Label *mExpTime15Label; - - Label *mLastKillExpLabel; - Label *mTimeBeforeJackoLabel; - - int m1minExpTime; - int m1minExpNum; - int m1minSpeed; - - int m5minExpTime; - int m5minExpNum; - int m5minSpeed; - - int m15minExpTime; - int m15minExpNum; - int m15minSpeed; - - int mJackoSpawnTime; - int mJackoId; - bool mIsJackoAlive; - bool mIsJackoMustSpawn; - bool mIsJackoSpawnTimeUnknown; -}; - -extern KillStats *killStats; - -#endif // GUI_KILLSTATS_H diff --git a/src/gui/logindialog.cpp b/src/gui/logindialog.cpp deleted file mode 100644 index f3d43c31b..000000000 --- a/src/gui/logindialog.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/logindialog.h" - -#include "client.h" -#include "configuration.h" - -#include "input/keydata.h" -#include "input/keyevent.h" - -#include "gui/confirmdialog.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/checkbox.h" -#include "gui/widgets/dropdown.h" -#include "gui/widgets/label.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/passwordfield.h" - -#include "net/charserverhandler.h" -#include "net/logindata.h" -#include "net/loginhandler.h" -#include "net/net.h" - -#include "utils/gettext.h" -#include "utils/paths.h" -#include "utils/process.h" - -#include "debug.h" - -std::string LoginDialog::savedPassword(""); -std::string LoginDialog::savedPasswordKey(""); - -struct OpenUrlListener : public gcn::ActionListener -{ - OpenUrlListener() : - gcn::ActionListener(), - url() - { - } - - A_DELETE_COPY(OpenUrlListener) - - void action(const gcn::ActionEvent &event) override - { - if (event.getId() == "yes") - openBrowser(url); - } - - std::string url; -} urlListener; - -const char *UPDATE_TYPE_TEXT[3] = -{ - // TRANSLATORS: update type - N_("Normal"), - // TRANSLATORS: update type - N_("Auto Close"), - // TRANSLATORS: update type - N_("Skip"), -}; - -class UpdateTypeModel final : public gcn::ListModel -{ - public: - UpdateTypeModel() - { } - - A_DELETE_COPY(UpdateTypeModel) - - ~UpdateTypeModel() - { } - - int getNumberOfElements() override - { - return 3; - } - - std::string getElementAt(int i) override - { - if (i >= getNumberOfElements() || i < 0) - return "???"; - return gettext(UPDATE_TYPE_TEXT[i]); - } -}; - -class UpdateListModel final : public gcn::ListModel -{ - public: - explicit UpdateListModel(LoginData *const data) : - gcn::ListModel(), - mLoginData(data) - { - } - - A_DELETE_COPY(UpdateListModel) - - ~UpdateListModel() - { } - - int getNumberOfElements() override - { - if (!mLoginData) - return 0; - return static_cast(mLoginData->updateHosts.size()); - } - - std::string getElementAt(int i) override - { - if (!mLoginData || i >= getNumberOfElements() || i < 0) - return "???"; - return mLoginData->updateHosts[i]; - } - - protected: - LoginData *mLoginData; -}; - -LoginDialog::LoginDialog(LoginData *const data, std::string serverName, - std::string *const updateHost): - // TRANSLATORS: login dialog name - Window(_("Login"), false, nullptr, "login.xml"), - gcn::ActionListener(), - gcn::KeyListener(), - mLoginData(data), - mUserField(new TextField(this, mLoginData->username)), - mPassField(new PasswordField(this, mLoginData->password)), - // TRANSLATORS: login dialog label - mKeepCheck(new CheckBox(this, _("Remember username"), - mLoginData->remember)), - // TRANSLATORS: login dialog label - mUpdateTypeLabel(new Label(this, _("Update:"))), - mUpdateHostLabel(nullptr), - mUpdateTypeModel(new UpdateTypeModel), - mUpdateTypeDropDown(new DropDown(this, mUpdateTypeModel)), - // TRANSLATORS: login dialog button - mServerButton(new Button(this, _("Change Server"), "server", this)), - // TRANSLATORS: login dialog button - mLoginButton(new Button(this, _("Login"), "login", this)), - // TRANSLATORS: login dialog button - mRegisterButton(new Button(this, _("Register"), "register", this)), - // TRANSLATORS: login dialog checkbox - mCustomUpdateHost(new CheckBox(this, _("Custom update host"), - mLoginData->updateType & LoginData::Upd_Custom, this, "customhost")), - mUpdateHostText(new TextField(this, serverConfig.getValue( - "customUpdateHost", ""))), - mUpdateListModel(nullptr), - mUpdateHostDropDown(nullptr), - mUpdateHost(updateHost), - mServerName(serverName) -{ - setCloseButton(true); - - Net::getCharServerHandler()->clear(); - - // TRANSLATORS: login dialog label - Label *const serverLabel1 = new Label(this, _("Server:")); - Label *const serverLabel2 = new Label(this, serverName); - serverLabel2->adjustSize(); - // TRANSLATORS: login dialog label - Label *const userLabel = new Label(this, _("Name:")); - // TRANSLATORS: login dialog label - Label *const passLabel = new Label(this, _("Password:")); - if (mLoginData && mLoginData->updateHosts.size() > 1) - { - // TRANSLATORS: login dialog label - mUpdateHostLabel = new Label(this, strprintf(_("Update host: %s"), - mLoginData->updateHost.c_str())); - mUpdateListModel = new UpdateListModel(mLoginData); - mUpdateHostDropDown = new DropDown(this, mUpdateListModel, - false, false, this, "updateselect"); - const std::string str = serverConfig.getValue("updateHost2", ""); - if (!str.empty()) - mUpdateHostDropDown->setSelectedString(str); - } - else - { - mUpdateHostLabel = nullptr; - mUpdateListModel = nullptr; - mUpdateHostDropDown = nullptr; - } - mUpdateHostText->adjustSize(); - - if (mPassField->getText().empty() && LoginDialog::savedPassword != "") - mPassField->setText(LoginDialog::savedPassword); - - mUpdateTypeDropDown->setActionEventId("updatetype"); - mUpdateTypeDropDown->setSelected((mLoginData->updateType - | LoginData::Upd_Custom) ^ LoginData::Upd_Custom); - - if (!mCustomUpdateHost->isSelected()) - mUpdateHostText->setVisible(false); - - mUserField->setActionEventId("login"); - mPassField->setActionEventId("login"); - - mUserField->addKeyListener(this); - mPassField->addKeyListener(this); - mUserField->addActionListener(this); - mPassField->addActionListener(this); - - place(0, 0, serverLabel1); - place(1, 0, serverLabel2, 8); - place(0, 1, userLabel); - place(1, 1, mUserField, 8); - place(0, 2, passLabel); - place(1, 2, mPassField, 8); - place(0, 6, mUpdateTypeLabel, 1); - place(1, 6, mUpdateTypeDropDown, 8); - int n = 7; - if (mUpdateHostLabel) - { - place(0, 7, mUpdateHostLabel, 9); - place(0, 8, mUpdateHostDropDown, 9); - n += 2; - } - place(0, n, mCustomUpdateHost, 9); - place(0, n + 1, mUpdateHostText, 9); - place(0, n + 2, mKeepCheck, 9); - place(0, n + 3, mRegisterButton).setHAlign(LayoutCell::LEFT); - place(2, n + 3, mServerButton); - place(3, n + 3, mLoginButton); - - addKeyListener(this); - if (mUpdateHostLabel) - setContentSize(310, 250); - else - setContentSize(310, 200); - - reflowLayout(); - center(); - setVisible(true); - - if (mUserField->getText().empty()) - mUserField->requestFocus(); - else - mPassField->requestFocus(); - - mLoginButton->setEnabled(canSubmit()); - mRegisterButton->setEnabled(Net::getLoginHandler()->isRegistrationEnabled() - || !mLoginData->registerUrl.empty()); -} - -LoginDialog::~LoginDialog() -{ - delete mUpdateTypeModel; - mUpdateTypeModel = nullptr; - delete mUpdateListModel; - mUpdateListModel = nullptr; -} - -void LoginDialog::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "login" && canSubmit()) - { - prepareUpdate(); - mLoginData->registerLogin = false; - client->setState(STATE_LOGIN_ATTEMPT); - } - else if (eventId == "server") - { - close(); - } - else if (eventId == "register") - { - if (Net::getLoginHandler()->isRegistrationEnabled()) - { - prepareUpdate(); - client->setState(STATE_REGISTER_PREP); - } - else if (!mLoginData->registerUrl.empty()) - { - const std::string &url = mLoginData->registerUrl; - urlListener.url = url; - // TRANSLATORS: question dialog - ConfirmDialog *const confirmDlg = new ConfirmDialog( - _("Open register url"), url, SOUND_REQUEST, false, true); - confirmDlg->addActionListener(&urlListener); - } - } - else if (eventId == "customhost") - { - mUpdateHostText->setVisible(mCustomUpdateHost->isSelected()); - } - else if (eventId == "updateselect") - { - mCustomUpdateHost->setSelected(false); - mUpdateHostText->setVisible(false); - } -} - -void LoginDialog::keyPressed(gcn::KeyEvent &keyEvent) -{ - if (keyEvent.isConsumed()) - { - mLoginButton->setEnabled(canSubmit()); - return; - } - - const int actionId = static_cast( - &keyEvent)->getActionId(); - if (actionId == static_cast(Input::KEY_GUI_CANCEL)) - { - action(gcn::ActionEvent(nullptr, mServerButton->getActionEventId())); - } - else if (actionId == static_cast(Input::KEY_GUI_SELECT) - || actionId == static_cast(Input::KEY_GUI_SELECT2)) - { - action(gcn::ActionEvent(nullptr, mLoginButton->getActionEventId())); - } - else - { - mLoginButton->setEnabled(canSubmit()); - } -} - -bool LoginDialog::canSubmit() const -{ - return !mUserField->getText().empty() && - !mPassField->getText().empty() && - client->getState() == STATE_LOGIN; -} - -void LoginDialog::prepareUpdate() -{ - mLoginData->username = mUserField->getText(); - mLoginData->password = mPassField->getText(); - mLoginData->remember = mKeepCheck->isSelected(); - int updateType = mUpdateTypeDropDown->getSelected(); - - if (mCustomUpdateHost->isSelected() - && !mUpdateHostText->getText().empty()) - { - updateType |= LoginData::Upd_Custom; - serverConfig.setValue("customUpdateHost", - mUpdateHostText->getText()); - - if (checkPath(mUpdateHostText->getText())) - { - mLoginData->updateHost = mUpdateHostText->getText(); - *mUpdateHost = mUpdateHostText->getText(); - } - else - { - mLoginData->updateHost.clear(); - (*mUpdateHost).clear(); - } - } - else - { - std::string str; - if (mUpdateHostDropDown) - { - str = mUpdateHostDropDown->getSelectedString(); - } - else if (mLoginData->updateHost.empty() - && !mLoginData->updateHosts.empty()) - { - str = mLoginData->updateHosts[0]; - } - serverConfig.setValue("updateHost2", str); - if (!str.empty() && checkPath(str)) - { - mLoginData->updateHost = str; - *mUpdateHost = str; - } - else - { - mLoginData->updateHost.clear(); - (*mUpdateHost).clear(); - } - } - - mLoginData->updateType = updateType; - serverConfig.setValue("updateType", updateType); - - mRegisterButton->setEnabled(false); - mServerButton->setEnabled(false); - mLoginButton->setEnabled(false); - - LoginDialog::savedPassword = mPassField->getText(); - if (mLoginData->remember) - LoginDialog::savedPasswordKey = mServerName; - else - LoginDialog::savedPasswordKey = "-"; -} - -void LoginDialog::close() -{ - client->setState(STATE_SWITCH_SERVER); - Window::close(); -} diff --git a/src/gui/logindialog.h b/src/gui/logindialog.h deleted file mode 100644 index fee0d4016..000000000 --- a/src/gui/logindialog.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_LOGINDIALOG_H -#define GUI_LOGINDIALOG_H - -#include "gui/widgets/window.h" - -#include -#include - -#include - -class Button; -class CheckBox; -class DropDown; -class Label; -class LoginData; -class TextField; -class UpdateListModel; -class UpdateTypeModel; - -/** - * The login dialog. - * - * \ingroup Interface - */ -class LoginDialog final : public Window, public gcn::ActionListener, - public gcn::KeyListener -{ - public: - /** - * Constructor - * - * @see Window::Window - */ - LoginDialog(LoginData *const data, std::string serverName, - std::string *const updateHost); - - A_DELETE_COPY(LoginDialog) - - ~LoginDialog(); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - /** - * Called when a key is pressed in one of the text fields. - */ - void keyPressed(gcn::KeyEvent &keyEvent) override; - - void close() override; - - static std::string savedPasswordKey; - static std::string savedPassword; - - private: - /** - * Returns whether submit can be enabled. This is true in the login - * state, when all necessary fields have some text. - */ - bool canSubmit() const; - - void prepareUpdate(); - - LoginData *mLoginData; - - TextField *mUserField; - TextField *mPassField; - CheckBox *mKeepCheck; - Label *mUpdateTypeLabel; - Label *mUpdateHostLabel; - UpdateTypeModel *mUpdateTypeModel; - DropDown *mUpdateTypeDropDown; - Button *mServerButton; - Button *mLoginButton; - Button *mRegisterButton; - CheckBox *mCustomUpdateHost; - TextField *mUpdateHostText; - UpdateListModel *mUpdateListModel; - DropDown *mUpdateHostDropDown; - - std::string *mUpdateHost; - std::string mServerName; -}; - -#endif // GUI_LOGINDIALOG_H diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp deleted file mode 100644 index 7164aa070..000000000 --- a/src/gui/minimap.cpp +++ /dev/null @@ -1,484 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/minimap.h" - -#include "actorspritemanager.h" -#include "client.h" -#include "configuration.h" -#include "party.h" - -#include "being/localplayer.h" - -#include "gui/setup.h" -#include "gui/viewport.h" -#include "gui/textpopup.h" - -#include "resources/image.h" -#include "resources/imagehelper.h" -#include "resources/resourcemanager.h" - -#include "utils/gettext.h" -#include "utils/sdlcheckutils.h" - -#include "debug.h" - -bool Minimap::mShow = true; - -Minimap::Minimap() : - // TRANSLATORS: mini map window name - Window(_("Map"), false, nullptr, "map.xml"), - mWidthProportion(0.5), - mHeightProportion(0.5), - mMapImage(nullptr), - mMapOriginX(0), - mMapOriginY(0), - mTextPopup(new TextPopup), - mCustomMapImage(false), - mAutoResize(config.getBoolValue("autoresizeminimaps")) -{ - setWindowName("Minimap"); - mShow = config.getValueBool(getWindowName() + "Show", true); - - config.addListener("autoresizeminimaps", this); - - setDefaultSize(5, 25, 100, 100); - // set this to false as the minimap window size is changed - // depending on the map size - setResizable(true); - if (setupWindow) - setupWindow->registerWindowForReset(this); - - setDefaultVisible(true); - setSaveVisible(true); - - setStickyButton(true); - setSticky(false); - - loadWindowState(); - setVisible(mShow, isSticky()); - enableVisibleSound(true); -} - -Minimap::~Minimap() -{ - config.setValue(getWindowName() + "Show", mShow); - config.removeListeners(this); - - if (mMapImage) - { - if (mCustomMapImage) - delete mMapImage; - else - mMapImage->decRef(); - mMapImage = nullptr; - } - delete mTextPopup; - mTextPopup = nullptr; -} - -void Minimap::setMap(const Map *const map) -{ - std::string caption; - - if (map) - caption = map->getName(); - - if (caption.empty()) - { - // TRANSLATORS: mini map window name - caption = _("Map"); - } - - setCaption(caption); - - // Adapt the image - if (mMapImage) - { - if (mCustomMapImage) - delete mMapImage; - else - mMapImage->decRef(); - mMapImage = nullptr; - } - - if (map) - { - if (config.getBoolValue("showExtMinimaps")) - { - SDL_Surface *const surface = MSDL_CreateRGBSurface(SDL_SWSURFACE, - map->getWidth(), map->getHeight(), 32, - 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000); - if (!surface) - { - if (!isSticky()) - setVisible(false); - return; - } - - // I'm not sure if the locks are necessary since it's a SWSURFACE - SDL_LockSurface(surface); - int* data = static_cast(surface->pixels); - if (!data) - { - if (!isSticky()) - setVisible(false); - return; - } - const int size = surface->h * surface->w; - const int mask = (Map::BLOCKMASK_WALL | Map::BLOCKMASK_AIR - | Map::BLOCKMASK_WATER); - - for (int ptr = 0; ptr < size; ptr ++) - *(data ++) = -!(map->mMetaTiles[ptr].blockmask & mask); - - SDL_UnlockSurface(surface); - - mMapImage = imageHelper->load(surface); - mMapImage->setAlpha(client->getGuiAlpha()); - mCustomMapImage = true; - MSDL_FreeSurface(surface); - } - else - { - std::string tempname = paths.getStringValue("minimaps").append( - map->getFilename()).append(".png"); - ResourceManager *const resman = ResourceManager::getInstance(); - - std::string minimapName = map->getProperty("minimap"); - - if (minimapName.empty() && resman->exists(tempname)) - minimapName = tempname; - - if (minimapName.empty()) - { - tempname = std::string("graphics/minimaps/").append( - map->getFilename()).append(".png"); - if (resman->exists(tempname)) - minimapName = tempname; - } - - mMapImage = resman->getImage(minimapName); - mCustomMapImage = false; - } - } - - if (mMapImage && map) - { - const int width = mMapImage->mBounds.w + 2 * getPadding(); - const int height = mMapImage->mBounds.h - + getTitleBarHeight() + getPadding(); - const int mapWidth = mMapImage->mBounds.w < 100 ? width : 100; - const int mapHeight = mMapImage->mBounds.h < 100 ? height : 100; - const int minWidth = mapWidth > 310 ? 310 : mapWidth; - const int minHeight = mapHeight > 220 ? 220 : mapHeight; - - setMinWidth(minWidth); - setMinHeight(minHeight); - - mWidthProportion = static_cast( - mMapImage->mBounds.w) / static_cast(map->getWidth()); - mHeightProportion = static_cast( - mMapImage->mBounds.h) / static_cast(map->getHeight()); - - setMaxWidth(width); - setMaxHeight(height); - if (mAutoResize) - { - setWidth(width); - setHeight(height); - } - - const gcn::Rectangle &rect = mDimension; - setDefaultSize(rect.x, rect.y, rect.width, rect.height); - resetToDefaultSize(); - - if (mShow) - setVisible(true); - } - else - { - if (!isSticky()) - setVisible(false); - } -} - -void Minimap::toggle() -{ - setVisible(!isWindowVisible(), isSticky()); - mShow = isWindowVisible(); -} - -void Minimap::draw(gcn::Graphics *graphics) -{ - BLOCK_START("Minimap::draw") - Window::draw(graphics); - - if (!userPalette || !player_node || !viewport) - { - BLOCK_END("Minimap::draw") - return; - } - - Graphics *const graph = static_cast(graphics); - - const gcn::Rectangle a = getChildrenArea(); - - graphics->pushClipArea(a); - - if (!actorSpriteManager) - { - BLOCK_END("Minimap::draw") - return; - } - - mMapOriginX = 0; - mMapOriginY = 0; - - if (mMapImage) - { - const SDL_Rect &rect = mMapImage->mBounds; - const int w = rect.w; - const int h = rect.h; - if (w > a.width || h > a.height) - { - const Vector &p = player_node->getPosition(); - mMapOriginX = (a.width / 2) - (p.x + static_cast( - viewport->getCameraRelativeX()) * mWidthProportion) / 32; - - mMapOriginY = (a.height / 2) - (p.y + static_cast( - viewport->getCameraRelativeY()) * mHeightProportion) / 32; - - const int minOriginX = a.width - w; - const int minOriginY = a.height - h; - - if (mMapOriginX < minOriginX) - mMapOriginX = minOriginX; - if (mMapOriginY < minOriginY) - mMapOriginY = minOriginY; - if (mMapOriginX > 0) - mMapOriginX = 0; - if (mMapOriginY > 0) - mMapOriginY = 0; - } - - graph->drawImage(mMapImage, mMapOriginX, mMapOriginY); - } - - const ActorSprites &actors = actorSpriteManager->getAll(); - FOR_EACH (ActorSpritesConstIterator, it, actors) - { - if (!(*it) || (*it)->getType() == ActorSprite::FLOOR_ITEM) - continue; - - const Being *const being = static_cast(*it); - if (!being) - continue; - - int dotSize = 2; - int type = UserPalette::PC; - - if (being == player_node) - { - type = UserPalette::SELF; - dotSize = 3; - } - else if (being->isGM()) - { - type = UserPalette::GM; - } - else if (being->getGuild() == player_node->getGuild() - || being->getGuildName() == player_node->getGuildName()) - { - type = UserPalette::GUILD; - } - else - { - switch (being->getType()) - { - case ActorSprite::MONSTER: - type = UserPalette::MONSTER; - break; - - case ActorSprite::NPC: - type = UserPalette::NPC; - break; - - case ActorSprite::AVATAR: - case ActorSprite::UNKNOWN: - case ActorSprite::PLAYER: - case ActorSprite::FLOOR_ITEM: - case ActorSprite::PORTAL: - case ActorSprite::PET: - default: - continue; - } - } - - if (userPalette) - graphics->setColor(userPalette->getColor(type)); - - const int offsetHeight = static_cast(static_cast( - dotSize - 1) * mHeightProportion); - const int offsetWidth = static_cast(static_cast( - dotSize - 1) * mWidthProportion); - const Vector &pos = being->getPosition(); - - graphics->fillRectangle(gcn::Rectangle( - static_cast(pos.x * mWidthProportion) / 32 - + mMapOriginX - offsetWidth, - static_cast(pos.y * mHeightProportion) / 32 - + mMapOriginY - offsetHeight, dotSize, dotSize)); - } - - if (player_node->isInParty()) - { - const Party *const party = player_node->getParty(); - if (party) - { - const PartyMember *const m = party->getMember( - player_node->getName()); - const Party::MemberList *const members = party->getMembers(); - if (m && members) - { - const std::string curMap = m->getMap(); - Party::MemberList::const_iterator it = members->begin(); - const Party::MemberList::const_iterator - it_end = members->end(); - while (it != it_end) - { - const PartyMember *const member = *it; - if (member && member->getMap() == curMap - && member->getOnline() && member != m) - { - if (userPalette) - { - graphics->setColor(userPalette->getColor( - UserPalette::PARTY)); - } - - const int offsetHeight = static_cast( - mHeightProportion); - const int offsetWidth = static_cast( - mWidthProportion); - - graphics->fillRectangle(gcn::Rectangle( - static_cast(member->getX() - * mWidthProportion) + mMapOriginX - offsetWidth, - static_cast(member->getY() - * mHeightProportion) + mMapOriginY - offsetHeight, - 2, 2)); - } - ++ it; - } - } - } - } - - const Vector &pos = player_node->getPosition(); - - const int gw = graph->getWidth(); - const int gh = graph->getHeight(); - int x = static_cast((pos.x - (gw / 2) - + viewport->getCameraRelativeX()) - * mWidthProportion) / 32 + mMapOriginX; - int y = static_cast((pos.y - (gh / 2) - + viewport->getCameraRelativeY()) - * mHeightProportion) / 32 + mMapOriginY; - - const int w = static_cast(static_cast( - gw) * mWidthProportion / 32); - const int h = static_cast(static_cast( - gh) * mHeightProportion / 32); - - if (w <= a.width) - { - if (x < 0 && w) - x = 0; - if (x + w > a.width) - x = a.width - w; - } - if (h <= a.height) - { - if (y < 0 && h) - y = 0; - if (y + h > a.height) - y = a.height - h; - } - - graphics->setColor(userPalette->getColor(UserPalette::PC)); - graphics->drawRectangle(gcn::Rectangle(x, y, w, h)); - graphics->popClipArea(); - BLOCK_END("Minimap::draw") -} - -void Minimap::mouseReleased(gcn::MouseEvent &event) -{ - Window::mouseReleased(event); - - if (!player_node || !viewport) - return; - - if (event.getButton() == gcn::MouseEvent::LEFT) - { - int x = event.getX(); - int y = event.getY(); - screenToMap(x, y); - - player_node->navigateTo(x, y); - } - else if (event.getButton() == gcn::MouseEvent::RIGHT) - { - int x = event.getX(); - int y = event.getY(); - screenToMap(x, y); - viewport->showMapPopup(x, y); - } -} - -void Minimap::mouseMoved(gcn::MouseEvent &event) -{ - Window::mouseMoved(event); - const int x = event.getX(); - const int y = event.getY(); - const gcn::Rectangle &rect = mDimension; - mTextPopup->show(x + rect.x, y + rect.y, mCaption); -} - -void Minimap::mouseExited(gcn::MouseEvent &event) -{ - Window::mouseExited(event); - mTextPopup->hide(); -} - -void Minimap::screenToMap(int &x, int &y) -{ - const gcn::Rectangle a = getChildrenArea(); - x = (x - a.x - mMapOriginX + mWidthProportion) / mWidthProportion; - y = (y - a.y - mMapOriginY + mHeightProportion) / mHeightProportion; -} - -void Minimap::optionChanged(const std::string &name) -{ - if (name == "autoresizeminimaps") - mAutoResize = config.getBoolValue("autoresizeminimaps"); -} diff --git a/src/gui/minimap.h b/src/gui/minimap.h deleted file mode 100644 index decacfec4..000000000 --- a/src/gui/minimap.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_MINIMAP_H -#define GUI_MINIMAP_H - -#include "gui/widgets/window.h" - -class Image; -class Map; -class TextPopup; - -/** - * Minimap window. Shows a minimap image and the name of the current map. - * - * The name of the map is defined by the map property "name". The minimap image - * is defined by the map property "minimap". The path to the image should be - * given relative to the root of the client data. - * - * \ingroup Interface - */ -class Minimap final : public Window, public ConfigListener -{ - public: - Minimap(); - - A_DELETE_COPY(Minimap) - - ~Minimap(); - - /** - * Sets the map image that should be displayed. - */ - void setMap(const Map *const map); - - /** - * Toggles the displaying of the minimap. - */ - void toggle(); - - /** - * Draws the minimap. - */ - void draw(gcn::Graphics *graphics) override; - - void mouseMoved(gcn::MouseEvent &event) override; - - void mouseReleased(gcn::MouseEvent &event) override; - - void mouseExited(gcn::MouseEvent &event) override; - - void screenToMap(int &x, int &y); - - void optionChanged(const std::string &name); - - private: - float mWidthProportion; - float mHeightProportion; - Image *mMapImage; - int mMapOriginX; - int mMapOriginY; - TextPopup *mTextPopup; - bool mCustomMapImage; - bool mAutoResize; - static bool mShow; -}; - -extern Minimap *minimap; - -#endif // GUI_MINIMAP_H diff --git a/src/gui/ministatuswindow.cpp b/src/gui/ministatuswindow.cpp deleted file mode 100644 index 5ab8a2b57..000000000 --- a/src/gui/ministatuswindow.cpp +++ /dev/null @@ -1,526 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/ministatuswindow.h" - -#include "animatedsprite.h" -#include "configuration.h" - -#include "being/localplayer.h" -#include "being/playerinfo.h" - -#include "gui/statuswindow.h" -#include "gui/statuspopup.h" -#include "gui/textpopup.h" -#include "gui/viewport.h" - -#include "gui/widgets/progressbar.h" - -#include "net/net.h" -#include "net/playerhandler.h" -#include "net/gamehandler.h" - -#include "utils/dtor.h" -#include "utils/gettext.h" - -#include "debug.h" - -extern volatile int tick_time; - -typedef std::vector ::const_iterator ProgressBarVectorCIter; - -MiniStatusWindow::MiniStatusWindow() : - Popup("MiniStatus", "ministatus.xml"), - InventoryListener(), - mBars(), - mBarNames(), - mIcons(), - mSpacing(mSkin ? mSkin->getOption("spacing", 3) : 3), - mIconPadding(mSkin ? mSkin->getOption("iconPadding", 3) : 3), - mIconSpacing(mSkin ? mSkin->getOption("iconSpacing", 2) : 2), - mMaxX(0), - // TRANSLATORS: status bar name - mHpBar(createBar(0, 100, 0, Theme::PROG_HP, "hp bar", _("health bar"))), - mMpBar(Net::getGameHandler()->canUseMagicBar() - ? createBar(0, 100, 0, Net::getPlayerHandler()->canUseMagic() - // TRANSLATORS: status bar name - ? Theme::PROG_MP : Theme::PROG_NO_MP, "mp bar", _("mana bar")) - : nullptr), - mXpBar(createBar(0, 100, 0, Theme::PROG_EXP, - // TRANSLATORS: status bar name - "xp bar", _("experience bar"))), - mJobBar(nullptr), - mWeightBar(createBar(0, 140, 0, Theme::PROG_WEIGHT, - // TRANSLATORS: status bar name - "weight bar", _("weight bar"))), - mInvSlotsBar(createBar(0, 45, 0, Theme::PROG_INVY_SLOTS, - // TRANSLATORS: status bar name - "inventory slots bar", _("inventory slots bar"))), - mMoneyBar(createBar(0, 130, 0, Theme::PROG_INVY_SLOTS, - // TRANSLATORS: status bar name - "money bar", _("money bar"))), - mArrowsBar(createBar(0, 50, 0, Theme::PROG_INVY_SLOTS, - // TRANSLATORS: status bar name - "arrows bar", _("arrows bar"))), - mStatusBar(createBar(100, (config.getIntValue("fontSize") > 16 - ? 250 : 165), 0, Theme::PROG_EXP, - // TRANSLATORS: status bar name - "status bar", _("status bar"))), - mTextPopup(new TextPopup), - mStatusPopup(new StatusPopup) -{ - listen(CHANNEL_ATTRIBUTES); - - StatusWindow::updateHPBar(mHpBar); - - if (Net::getGameHandler()->canUseMagicBar()) - StatusWindow::updateMPBar(mMpBar); - - const int job = Net::getPlayerHandler()->getJobLocation() - && serverConfig.getValueBool("showJob", true); - - StatusWindow::updateXPBar(mXpBar); - - if (job) - { - mJobBar = createBar(0, 100, 0, Theme::PROG_JOB, "job bar", - // TRANSLATORS: status bar name - _("job bar")); - StatusWindow::updateJobBar(mJobBar); - } - - loadBars(); - updateBars(); - - setVisible(config.getValueBool(getPopupName() + "Visible", true)); - addMouseListener(this); - Inventory *const inv = PlayerInfo::getInventory(); - if (inv) - inv->addInventoyListener(this); - - StatusWindow::updateMoneyBar(mMoneyBar); - StatusWindow::updateArrowsBar(mArrowsBar); - updateStatus(); -} - -MiniStatusWindow::~MiniStatusWindow() -{ - delete mTextPopup; - mTextPopup = nullptr; - delete mStatusPopup; - mStatusPopup = nullptr; - delete_all(mIcons); - mIcons.clear(); - - Inventory *const inv = PlayerInfo::getInventory(); - if (inv) - inv->removeInventoyListener(this); - - FOR_EACH (ProgressBarVectorCIter, it, mBars) - { - ProgressBar *bar = *it; - if (!bar) - continue; - if (!bar->isVisible()) - delete bar; - } - mBars.clear(); -} - -ProgressBar *MiniStatusWindow::createBar(const float progress, - const int width, const int height, - const int color, - const std::string &name, - const std::string &description) -{ - ProgressBar *const bar = new ProgressBar(this, - progress, width, height, color); - bar->setActionEventId(name); - bar->setId(description); - mBars.push_back(bar); - mBarNames[name] = bar; - return bar; -} - -void MiniStatusWindow::updateBars() -{ - int x = 0; - const ProgressBar *lastBar = nullptr; - FOR_EACH (ProgressBarVectorCIter, it, mBars) - safeRemove(*it); - - FOR_EACH (ProgressBarVectorCIter, it, mBars) - { - ProgressBar *const bar = *it; - if (!bar) - continue; - if (bar->isVisible()) - { - bar->setPosition(x, 0); - add(bar); - x += bar->getWidth() + mSpacing; - lastBar = bar; - } - } - - if (lastBar) - { - setContentSize(lastBar->getX() + lastBar->getWidth(), - lastBar->getY() + lastBar->getHeight()); - } - mMaxX = x; -} - -void MiniStatusWindow::setIcon(const int index, AnimatedSprite *const sprite) -{ - if (index >= static_cast(mIcons.size())) - mIcons.resize(index + 1, nullptr); - - delete mIcons[index]; - mIcons[index] = sprite; -} - -void MiniStatusWindow::eraseIcon(const int index) -{ - if (index < static_cast(mIcons.size())) - { - delete mIcons[index]; - mIcons.erase(mIcons.begin() + index); - } -} - -void MiniStatusWindow::drawIcons(Graphics *const graphics) -{ - // Draw icons - int icon_x = mMaxX + mIconPadding; - for (size_t i = 0, sz = mIcons.size(); i < sz; i ++) - { - const AnimatedSprite *const icon = mIcons[i]; - if (icon) - { - icon->draw(graphics, icon_x, mIconPadding); - icon_x += mIconSpacing + icon->getWidth(); - } - } -} - -void MiniStatusWindow::processEvent(const Channels channel A_UNUSED, - const DepricatedEvent &event) -{ - if (event.getName() == EVENT_UPDATEATTRIBUTE) - { - const int id = event.getInt("id"); - if (id == PlayerInfo::HP || id == PlayerInfo::MAX_HP) - { - StatusWindow::updateHPBar(mHpBar); - } - else if (id == PlayerInfo::MP || id == PlayerInfo::MAX_MP) - { - StatusWindow::updateMPBar(mMpBar); - } - else if (id == PlayerInfo::EXP || id == PlayerInfo::EXP_NEEDED) - { - StatusWindow::updateXPBar(mXpBar); - } - else if (id == PlayerInfo::TOTAL_WEIGHT - || id == PlayerInfo::MAX_WEIGHT) - { - StatusWindow::updateWeightBar(mWeightBar); - } - else if (id == PlayerInfo::MONEY) - { - StatusWindow::updateMoneyBar(mMoneyBar); - } - } - else if (event.getName() == EVENT_UPDATESTAT) - { - StatusWindow::updateMPBar(mMpBar); - StatusWindow::updateJobBar(mJobBar); - } -} - -void MiniStatusWindow::updateStatus() -{ - StatusWindow::updateStatusBar(mStatusBar); - if (mStatusPopup && mStatusPopup->isPopupVisible()) - mStatusPopup->update(); -} - -void MiniStatusWindow::logic() -{ - BLOCK_START("MiniStatusWindow::logic") - Popup::logic(); - - for (size_t i = 0, sz = mIcons.size(); i < sz; i++) - { - AnimatedSprite *const icon = mIcons[i]; - if (icon) - icon->update(tick_time * 10); - } - BLOCK_END("MiniStatusWindow::logic") -} - -void MiniStatusWindow::draw(gcn::Graphics *graphics) -{ - BLOCK_START("MiniStatusWindow::draw") - drawChildren(graphics); - BLOCK_END("MiniStatusWindow::draw") -} - -void MiniStatusWindow::mouseMoved(gcn::MouseEvent &event) -{ - Popup::mouseMoved(event); - - const int x = event.getX(); - const int y = event.getY(); - - const gcn::Rectangle &rect = mDimension; - if (event.getSource() == mStatusBar) - { - mStatusPopup->view(x + rect.x, y + rect.y); - mTextPopup->hide(); - } - else if (event.getSource() == mXpBar) - { - std::string level; - if (player_node && player_node->isGM()) - { - // TRANSLATORS: status bar label - level = strprintf(_("Level: %d (GM %d)"), - PlayerInfo::getAttribute(PlayerInfo::LEVEL), - player_node->getGMLevel()); - } - else - { - // TRANSLATORS: status bar label - level = strprintf(_("Level: %d"), - PlayerInfo::getAttribute(PlayerInfo::LEVEL)); - } - - const int exp = PlayerInfo::getAttribute(PlayerInfo::EXP); - const int expNeed = PlayerInfo::getAttribute(PlayerInfo::EXP_NEEDED); - if (exp > expNeed) - { - mTextPopup->show(x + rect.x, y + rect.y, level, strprintf("%d/%d", - exp, expNeed)); - } - else - { - mTextPopup->show(x + rect.x, y + rect.y, level, strprintf("%d/%d", - exp, expNeed), - // TRANSLATORS: status bar label - strprintf("%s: %d", _("Need"), expNeed - exp)); - } - mStatusPopup->hide(); - } - else if (event.getSource() == mHpBar) - { - mTextPopup->show(x + rect.x, y + rect.y, event.getSource()->getId(), - strprintf("%d/%d", PlayerInfo::getAttribute(PlayerInfo::HP), - PlayerInfo::getAttribute(PlayerInfo::MAX_HP))); - mStatusPopup->hide(); - } - else if (event.getSource() == mMpBar) - { - mTextPopup->show(x + rect.x, y + rect.y, event.getSource()->getId(), - strprintf("%d/%d", PlayerInfo::getAttribute(PlayerInfo::MP), - PlayerInfo::getAttribute(PlayerInfo::MAX_MP))); - mStatusPopup->hide(); - } - else if (event.getSource() == mJobBar) - { - const std::pair exp = PlayerInfo::getStatExperience( - Net::getPlayerHandler()->getJobLocation()); - - // TRANSLATORS: job bar label - const std::string level = strprintf(_("Job level: %d"), - PlayerInfo::getStatBase( - Net::getPlayerHandler()->getJobLocation())); - - if (exp.first > exp.second) - { - mTextPopup->show(x + rect.x, y + rect.y, level, - strprintf("%d/%d", exp.first, exp.second)); - } - else - { - mTextPopup->show(x + rect.x, y + rect.y, level, - strprintf("%d/%d", exp.first, exp.second), - // TRANSLATORS: status bar label - strprintf("%s: %d", _("Need"), exp.second - exp.first)); - } - mStatusPopup->hide(); - } - else if (event.getSource() == mWeightBar) - { - mTextPopup->show(x + rect.x, y + rect.y, event.getSource()->getId(), - strprintf("%d/%d", PlayerInfo::getAttribute( - PlayerInfo::TOTAL_WEIGHT), - PlayerInfo::getAttribute(PlayerInfo::MAX_WEIGHT))); - mStatusPopup->hide(); - } - else if (event.getSource() == mInvSlotsBar) - { - const Inventory *const inv = PlayerInfo::getInventory(); - if (inv) - { - const int usedSlots = inv->getNumberOfSlotsUsed(); - const int maxSlots = inv->getSize(); - mTextPopup->show(x + rect.x, y + rect.y, - event.getSource()->getId(), - strprintf("%d/%d", usedSlots, maxSlots)); - } - mStatusPopup->hide(); - } - else if (event.getSource() == mMoneyBar) - { - mTextPopup->show(x + rect.x, y + rect.y, - event.getSource()->getId(), - toString(PlayerInfo::getAttribute(PlayerInfo::MONEY))); - } - else - { - mTextPopup->hide(); - mStatusPopup->hide(); - } -} - -void MiniStatusWindow::mousePressed(gcn::MouseEvent &event) -{ - if (!viewport) - return; - - if (event.getButton() == gcn::MouseEvent::RIGHT) - { - const ProgressBar *const bar = dynamic_cast( - event.getSource()); - if (!bar) - return; - if (viewport) - { - viewport->showPopup(getX() + event.getX(), - getY() + event.getY(), bar); - } - } -} - -void MiniStatusWindow::mouseExited(gcn::MouseEvent &event) -{ - Popup::mouseExited(event); - - mTextPopup->hide(); - mStatusPopup->hide(); -} - -void MiniStatusWindow::showBar(const std::string &name, const bool visible) -{ - ProgressBar *const bar = mBarNames[name]; - if (!bar) - return; - bar->setVisible(visible); - updateBars(); - saveBars(); -} - -void MiniStatusWindow::loadBars() -{ - if (!config.getIntValue("ministatussaved")) - { - if (mWeightBar) - mWeightBar->setVisible(false); - if (mInvSlotsBar) - mInvSlotsBar->setVisible(false); - if (mMoneyBar) - mMoneyBar->setVisible(false); - if (mArrowsBar) - mArrowsBar->setVisible(false); - if (mStatusBar) - mStatusBar->setVisible(false); - if (mJobBar) - mJobBar->setVisible(false); - return; - } - - for (int f = 0; f < 10; f ++) - { - const std::string str = config.getValue( - "ministatus" + toString(f), ""); - if (str == "") - continue; - ProgressBar *const bar = mBarNames[str]; - if (!bar) - continue; - bar->setVisible(false); - } -} - -void MiniStatusWindow::saveBars() const -{ - int i = 0; - FOR_EACH (ProgressBarVectorCIter, it, mBars) - { - const ProgressBar *const bar = *it; - if (!bar->isVisible()) - { - config.setValue("ministatus" + toString(i), - bar->getActionEventId()); - i ++; - } - } - for (int f = i; f < 10; f ++) - config.deleteKey("ministatus" + toString(f)); - - config.setValue("ministatussaved", true); -} - -void MiniStatusWindow::slotsChanged(Inventory *const inventory) -{ - if (!inventory) - return; - - if (inventory->getType() == Inventory::INVENTORY) - StatusWindow::updateInvSlotsBar(mInvSlotsBar); -} - -void MiniStatusWindow::updateArrows() -{ - StatusWindow::updateArrowsBar(mArrowsBar); -} - -gcn::Rectangle MiniStatusWindow::getChildrenArea() -{ - const int padding = mPadding; - const int padding2 = padding * 2; - const gcn::Rectangle &rect = mDimension; - return gcn::Rectangle(padding, padding, - rect.width - padding2, - rect.height - padding2); -} - -#ifdef USE_PROFILER -void MiniStatusWindow::logicChildren() -{ - BLOCK_START("MiniStatusWindow::logicChildren") - BasicContainer::logicChildren(); - BLOCK_END("MiniStatusWindow::logicChildren") -} -#endif diff --git a/src/gui/ministatuswindow.h b/src/gui/ministatuswindow.h deleted file mode 100644 index 39d1e689d..000000000 --- a/src/gui/ministatuswindow.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_MINISTATUSWINDOW_H -#define GUI_MINISTATUSWINDOW_H - -#include "inventory.h" -#include "depricatedlistener.h" - -#include "gui/widgets/popup.h" - -#include - -class AnimatedSprite; -class Graphics; -class ProgressBar; -class StatusPopup; -class TextPopup; - -/** - * The player mini-status dialog. - * - * \ingroup Interface - */ -class MiniStatusWindow final : public Popup, - public InventoryListener, - public DepricatedListener -{ - public: - MiniStatusWindow(); - - A_DELETE_COPY(MiniStatusWindow) - - ~MiniStatusWindow(); - - /** - * Sets one of the icons. - */ - void setIcon(const int index, AnimatedSprite *const sprite); - - void eraseIcon(const int index); - - void drawIcons(Graphics *const graphics); - - void processEvent(const Channels channel, - const DepricatedEvent &event) override; - - void updateStatus(); - - void logic() override; - - void draw(gcn::Graphics *graphics) override; - - void mouseMoved(gcn::MouseEvent &mouseEvent) override; - - void mousePressed(gcn::MouseEvent &event) override; - - void mouseExited(gcn::MouseEvent &event) override; - - void showBar(const std::string &name, const bool visible); - - void updateBars(); - - void updateArrows(); - - void slotsChanged(Inventory *const inventory) override; - - std::vector &getBars() A_WARN_UNUSED - { return mBars; } - - gcn::Rectangle getChildrenArea() override A_WARN_UNUSED; - -#ifdef USE_PROFILER - void logicChildren(); -#endif - - private: - bool isInBar(ProgressBar *bar, int x, int y) const; - - ProgressBar *createBar(const float progress, const int width, - const int height, const int color, - const std::string &name, - const std::string &description) A_WARN_UNUSED; - - void loadBars(); - - void saveBars() const; - - std::vector mBars; - std::map mBarNames; - std::vector mIcons; - - int mSpacing; - int mIconPadding; - int mIconSpacing; - int mMaxX; - - /* - * Mini Status Bars - */ - ProgressBar *mHpBar; - ProgressBar *mMpBar; - ProgressBar *mXpBar; - ProgressBar *mJobBar; - ProgressBar *mWeightBar; - ProgressBar *mInvSlotsBar; - ProgressBar *mMoneyBar; - ProgressBar *mArrowsBar; - ProgressBar *mStatusBar; - TextPopup *mTextPopup; - StatusPopup *mStatusPopup; -}; - -extern MiniStatusWindow *miniStatusWindow; - -#endif // GUI_MINISTATUSWINDOW_H diff --git a/src/gui/npcdialog.cpp b/src/gui/npcdialog.cpp deleted file mode 100644 index 8a7466f4b..000000000 --- a/src/gui/npcdialog.cpp +++ /dev/null @@ -1,960 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/npcdialog.h" - -#include "actorspritemanager.h" -#include "configuration.h" -#include "client.h" -#include "inventory.h" -#include "item.h" -#include "soundconsts.h" -#include "soundmanager.h" - -#include "being/being.h" - -#include "gui/gui.h" -#include "gui/inventorywindow.h" -#include "gui/sdlfont.h" -#include "gui/viewport.h" - -#include "gui/widgets/browserbox.h" -#include "gui/widgets/button.h" -#include "gui/widgets/inttextfield.h" -#include "gui/widgets/itemcontainer.h" -#include "gui/widgets/itemlinkhandler.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/extendedlistbox.h" -#include "gui/widgets/playerbox.h" -#include "gui/widgets/scrollarea.h" - -#include "resources/avatardb.h" -#include "resources/npcdb.h" -#include "resources/resourcemanager.h" - -#include "net/net.h" -#include "net/npchandler.h" - -#include "utils/copynpaste.h" -#include "utils/gettext.h" - -#include - -#include "debug.h" - -// TRANSLATORS: npc dialog button -#define CAPTION_WAITING _("Stop waiting") -// TRANSLATORS: npc dialog button -#define CAPTION_NEXT _("Next") -// TRANSLATORS: npc dialog button -#define CAPTION_CLOSE _("Close") -// TRANSLATORS: npc dialog button -#define CAPTION_SUBMIT _("Submit") - -NpcDialog::DialogList NpcDialog::instances; -NpcDialogs NpcDialog::mNpcDialogs; - -typedef std::vector::iterator ImageVectorIter; - -NpcDialog::NpcDialog(const int npcId) : - // TRANSLATORS: npc dialog name - Window(_("NPC"), false, nullptr, "npc.xml"), - gcn::ActionListener(), - mNpcId(npcId), - mDefaultInt(0), - mDefaultString(), - mTextBox(new BrowserBox(this, BrowserBox::AUTO_WRAP)), - mScrollArea(new ScrollArea(mTextBox, - getOptionBool("showtextbackground"), "npc_textbackground.xml")), - mText(), - mNewText(), - mItemList(new ExtendedListBox(this, this, "extendedlistbox.xml")), - mListScrollArea(new ScrollArea(mItemList, - getOptionBool("showlistbackground"), "npc_listbackground.xml")), - mItems(), - mImages(), - mItemLinkHandler(new ItemLinkHandler), - mTextField(new TextField(this, "")), - mIntField(new IntTextField(this)), - // TRANSLATORS: npc dialog button - mPlusButton(new Button(this, _("+"), "inc", this)), - // TRANSLATORS: npc dialog button - mMinusButton(new Button(this, _("-"), "dec", this)), - // TRANSLATORS: npc dialog button - mClearButton(new Button(this, _("Clear"), "clear", this)), - mButton(new Button(this, "", "ok", this)), - // TRANSLATORS: npc dialog button - mButton2(new Button(this, _("Close"), "close", this)), - // TRANSLATORS: npc dialog button - mButton3(new Button(this, _("Add"), "add", this)), - // TRANSLATORS: npc dialog button - mResetButton(new Button(this, _("Reset"), "reset", this)), - mInventory(new Inventory(Inventory::NPC, 1)), - mItemContainer(new ItemContainer(this, mInventory)), - mItemScrollArea(new ScrollArea(mItemContainer, - getOptionBool("showitemsbackground"), "npc_listbackground.xml")), - mInputState(NPC_INPUT_NONE), - mActionState(NPC_ACTION_WAIT), - mLastNextTime(0), - mCameraMode(-1), - mCameraX(0), - mCameraY(0), - mPlayerBox(new PlayerBox(nullptr)), - mAvatarBeing(nullptr), - mShowAvatar(false), - mLogInteraction(config.getBoolValue("logNpcInGui")) -{ - // Basic Window Setup - setWindowName("NpcText"); - setResizable(true); - setFocusable(true); - setStickyButtonLock(true); - - setMinWidth(200); - setMinHeight(150); - - setDefaultSize(300, 578, ImageRect::LOWER_LEFT); - - mPlayerBox->setWidth(70); - mPlayerBox->setHeight(100); - - // Setup output text box - mTextBox->setOpaque(false); - mTextBox->setMaxRow(config.getIntValue("ChatLogLength")); - mTextBox->setLinkHandler(mItemLinkHandler); - mTextBox->setFont(gui->getNpcFont()); - mTextBox->setEnableKeys(true); - mTextBox->setEnableTabs(true); - - mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - mScrollArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); - - // Setup listbox - mItemList->setWrappingEnabled(true); - mItemList->setActionEventId("ok"); - mItemList->addActionListener(this); - mItemList->setDistributeMousePressed(false); - mItemList->setFont(gui->getNpcFont()); - if (gui->getNpcFont()->getHeight() < 20) - mItemList->setRowHeight(20); - else - mItemList->setRowHeight(gui->getNpcFont()->getHeight()); - - setContentSize(260, 175); - mListScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - mItemScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - mItemList->setVisible(true); - mTextField->setVisible(true); - mIntField->setVisible(true); - - const gcn::Font *const fnt = mButton->getFont(); - int width = std::max(fnt->getWidth(CAPTION_WAITING), - fnt->getWidth(CAPTION_NEXT)); - width = std::max(width, fnt->getWidth(CAPTION_CLOSE)); - width = std::max(width, fnt->getWidth(CAPTION_SUBMIT)); - mButton->setWidth(8 + width); - - // Place widgets - buildLayout(); - - center(); - loadWindowState(); - - instances.push_back(this); - setVisible(true); - requestFocus(); - enableVisibleSound(true); - soundManager.playGuiSound(SOUND_SHOW_WINDOW); - - if (actorSpriteManager) - { - const Being *const being = actorSpriteManager->findBeing(mNpcId); - if (being) - { - showAvatar(NPCDB::getAvatarFor(being->getSubType())); - setCaption(being->getName()); - } - } - - config.addListener("logNpcInGui", this); -} - -NpcDialog::~NpcDialog() -{ - config.removeListeners(this); - clearLayout(); - - if (mPlayerBox) - { - delete mPlayerBox->getBeing(); - delete mPlayerBox; - } - - delete mTextBox; - mTextBox = nullptr; - delete mClearButton; - mClearButton = nullptr; - delete mButton; - mButton = nullptr; - delete mButton2; - mButton2 = nullptr; - delete mButton3; - mButton3 = nullptr; - - // These might not actually be in the layout, so lets be safe - delete mScrollArea; - mScrollArea = nullptr; - delete mItemList; - mItemList = nullptr; - delete mTextField; - mTextField = nullptr; - delete mIntField; - mIntField = nullptr; - delete mResetButton; - mResetButton = nullptr; - delete mPlusButton; - mPlusButton = nullptr; - delete mMinusButton; - mMinusButton = nullptr; - delete mItemLinkHandler; - mItemLinkHandler = nullptr; - - delete mItemContainer; - mItemContainer = nullptr; - delete mInventory; - mInventory = nullptr; - delete mItemScrollArea; - mItemScrollArea = nullptr; - - delete mListScrollArea; - mListScrollArea = nullptr; - - FOR_EACH (ImageVectorIter, it, mImages) - { - if (*it) - (*it)->decRef(); - } - - mImages.clear(); - - instances.remove(this); -} - -void NpcDialog::addText(const std::string &text, const bool save) -{ - if (save || mLogInteraction) - { - if (mText.size() > 5000) - mText.clear(); - - mNewText.append(text); - mTextBox->addRow(text); - } - mScrollArea->setVerticalScrollAmount(mScrollArea->getVerticalMaxScroll()); - mActionState = NPC_ACTION_WAIT; - buildLayout(); -} - -void NpcDialog::showNextButton() -{ - mActionState = NPC_ACTION_NEXT; - buildLayout(); -} - -void NpcDialog::showCloseButton() -{ - mActionState = NPC_ACTION_CLOSE; - buildLayout(); -} - -void NpcDialog::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "ok") - { - if (mActionState == NPC_ACTION_NEXT) - { - if (!client->limitPackets(PACKET_NPC_NEXT)) - return; - - nextDialog(); - addText(std::string(), false); - } - else if (mActionState == NPC_ACTION_CLOSE - || mActionState == NPC_ACTION_WAIT) - { - closeDialog(); - } - else if (mActionState == NPC_ACTION_INPUT) - { - std::string printText; // Text that will get printed - // in the textbox - switch (mInputState) - { - case NPC_INPUT_LIST: - { - if (gui) - gui->resetClickCount(); - const int selectedIndex = mItemList->getSelected(); - - if (selectedIndex >= static_cast(mItems.size()) - || selectedIndex < 0 - || !client->limitPackets(PACKET_NPC_INPUT)) - { - return; - } - unsigned char choice = static_cast( - selectedIndex + 1); - printText = mItems[selectedIndex]; - - Net::getNpcHandler()->listInput(mNpcId, choice); - break; - } - case NPC_INPUT_STRING: - { - if (!client->limitPackets(PACKET_NPC_INPUT)) - return; - printText = mTextField->getText(); - Net::getNpcHandler()->stringInput(mNpcId, printText); - break; - } - case NPC_INPUT_INTEGER: - { - if (!client->limitPackets(PACKET_NPC_INPUT)) - return; - printText = strprintf("%d", mIntField->getValue()); - Net::getNpcHandler()->integerInput( - mNpcId, mIntField->getValue()); - break; - } - case NPC_INPUT_ITEM: - { - if (!client->limitPackets(PACKET_NPC_INPUT)) - return; - - const Item *const item = mInventory->getItem(0); - std::string str; - if (item) - { - str = strprintf("%d,%d", item->getId(), - item->getColor()); - } - else - { - str = "0,0"; - } - - // need send selected item - Net::getNpcHandler()->stringInput(mNpcId, str); - mInventory->clear(); - break; - } - - case NPC_INPUT_NONE: - default: - break; - } - if (mInputState != NPC_INPUT_ITEM) - { - // addText will auto remove the input layout - addText(strprintf("> \"%s\"", printText.c_str()), false); - } - mNewText.clear(); - } - - if (!mLogInteraction) - mTextBox->clearRows(); - } - else if (eventId == "reset") - { - switch (mInputState) - { - case NPC_INPUT_STRING: - mTextField->setText(mDefaultString); - break; - case NPC_INPUT_INTEGER: - mIntField->setValue(mDefaultInt); - break; - case NPC_INPUT_ITEM: - mInventory->clear(); - break; - case NPC_INPUT_NONE: - case NPC_INPUT_LIST: - default: - break; - } - } - else if (eventId == "inc") - { - mIntField->setValue(mIntField->getValue() + 1); - } - else if (eventId == "dec") - { - mIntField->setValue(mIntField->getValue() - 1); - } - else if (eventId == "clear") - { - switch (mInputState) - { - case NPC_INPUT_ITEM: - mInventory->clear(); - break; - case NPC_INPUT_STRING: - case NPC_INPUT_INTEGER: - case NPC_INPUT_LIST: - case NPC_INPUT_NONE: - default: - clearRows(); - break; - } - } - else if (eventId == "close") - { - if (mActionState == NPC_ACTION_INPUT) - { - switch (mInputState) - { - case NPC_INPUT_ITEM: - Net::getNpcHandler()->stringInput(mNpcId, "0,0"); - break; - case NPC_INPUT_STRING: - case NPC_INPUT_INTEGER: - case NPC_INPUT_NONE: - case NPC_INPUT_LIST: - default: - Net::getNpcHandler()->listInput(mNpcId, 255); - break; - } - closeDialog(); - } - } - else if (eventId == "add") - { - if (inventoryWindow) - { - const Item *const item = inventoryWindow->getSelectedItem(); - if (item) - mInventory->addItem(item->getId(), 1, 1, item->getColor()); - } - } -} - -void NpcDialog::nextDialog() -{ - Net::getNpcHandler()->nextDialog(mNpcId); -} - -void NpcDialog::closeDialog() -{ - restoreCamera(); - Net::getNpcHandler()->closeDialog(mNpcId); -} - -int NpcDialog::getNumberOfElements() -{ - return static_cast(mItems.size()); -} - -std::string NpcDialog::getElementAt(int i) -{ - return mItems[i]; -} - -const Image *NpcDialog::getImageAt(int i) -{ - return mImages[i]; -} - -void NpcDialog::choiceRequest() -{ - mItems.clear(); - FOR_EACH (ImageVectorIter, it, mImages) - { - if (*it) - (*it)->decRef(); - } - mImages.clear(); - mActionState = NPC_ACTION_INPUT; - mInputState = NPC_INPUT_LIST; - buildLayout(); -} - -void NpcDialog::addChoice(const std::string &choice) -{ - mItems.push_back(choice); - mImages.push_back(nullptr); -} - -void NpcDialog::parseListItems(const std::string &itemString) -{ - std::istringstream iss(itemString); - ResourceManager *const resman = ResourceManager::getInstance(); - - std::string tmp; - const std::string path = paths.getStringValue("guiIcons"); - while (getline(iss, tmp, ':')) - { - const size_t pos = tmp.find("|"); - if (pos == std::string::npos) - { - mItems.push_back(tmp); - mImages.push_back(nullptr); - } - else - { - mItems.push_back(tmp.substr(pos + 1)); - Image *const img = resman->getImage(std::string( - path).append(tmp.substr(0, pos)).append(".png")); - mImages.push_back(img); - } - } - - if (!mItems.empty()) - { - mItemList->setSelected(0); - mItemList->requestFocus(); - } - else - { - mItemList->setSelected(-1); - } -} - -void NpcDialog::refocus() -{ - if (!mItems.empty()) - mItemList->refocus(); -} - -void NpcDialog::textRequest(const std::string &defaultText) -{ - mActionState = NPC_ACTION_INPUT; - mInputState = NPC_INPUT_STRING; - mDefaultString = defaultText; - mTextField->setText(defaultText); - - buildLayout(); -} - -bool NpcDialog::isTextInputFocused() const -{ - return mTextField->isFocused(); -} - -bool NpcDialog::isInputFocused() const -{ - return mTextField->isFocused() || mIntField->isFocused() - || mItemList->isFocused(); -} - -bool NpcDialog::isAnyInputFocused() -{ - FOR_EACH (DialogList::const_iterator, it, instances) - { - if ((*it) && (*it)->isInputFocused()) - return true; - } - - return false; -} - -void NpcDialog::integerRequest(const int defaultValue, const int min, - const int max) -{ - mActionState = NPC_ACTION_INPUT; - mInputState = NPC_INPUT_INTEGER; - mDefaultInt = defaultValue; - mIntField->setRange(min, max); - mIntField->setValue(defaultValue); - buildLayout(); -} - -void NpcDialog::itemRequest() -{ - mActionState = NPC_ACTION_INPUT; - mInputState = NPC_INPUT_ITEM; - - buildLayout(); -} - -void NpcDialog::move(const int amount) -{ - if (mActionState != NPC_ACTION_INPUT) - return; - - switch (mInputState) - { - case NPC_INPUT_INTEGER: - mIntField->setValue(mIntField->getValue() + amount); - break; - case NPC_INPUT_LIST: - mItemList->setSelected(mItemList->getSelected() - amount); - break; - case NPC_INPUT_NONE: - case NPC_INPUT_STRING: - case NPC_INPUT_ITEM: - default: - break; - } -} - -void NpcDialog::setVisible(bool visible) -{ - Window::setVisible(visible); - - if (!visible) - scheduleDelete(); -} - -void NpcDialog::optionChanged(const std::string &name) -{ - if (name == "logNpcInGui") - mLogInteraction = config.getBoolValue("logNpcInGui"); -} - -NpcDialog *NpcDialog::getActive() -{ - if (instances.size() == 1) - return instances.front(); - - FOR_EACH (DialogList::const_iterator, it, instances) - { - if ((*it) && (*it)->isFocused()) - return (*it); - } - - return nullptr; -} - -void NpcDialog::closeAll() -{ - FOR_EACH (DialogList::const_iterator, it, instances) - { - if (*it) - (*it)->close(); - } -} - -void NpcDialog::placeNormalControls() -{ - if (mShowAvatar) - { - place(0, 0, mPlayerBox); - place(1, 0, mScrollArea, 5, 3); - place(4, 3, mClearButton); - place(5, 3, mButton); - } - else - { - place(0, 0, mScrollArea, 5, 3); - place(3, 3, mClearButton); - place(4, 3, mButton); - } -} - -void NpcDialog::placeMenuControls() -{ - if (mShowAvatar) - { - place(0, 0, mPlayerBox); - place(1, 0, mScrollArea, 6, 3); - place(0, 3, mListScrollArea, 7, 3); - place(1, 6, mButton2, 2); - place(3, 6, mClearButton, 2); - place(5, 6, mButton, 2); - } - else - { - place(0, 0, mScrollArea, 6, 3); - place(0, 3, mListScrollArea, 6, 3); - place(0, 6, mButton2, 2); - place(2, 6, mClearButton, 2); - place(4, 6, mButton, 2); - } -} - -void NpcDialog::placeTextInputControls() -{ - if (mShowAvatar) - { - place(0, 0, mPlayerBox); - place(1, 0, mScrollArea, 6, 3); - place(0, 3, mTextField, 6); - place(0, 4, mResetButton, 2); - place(4, 4, mClearButton, 2); - place(5, 4, mButton, 2); - } - else - { - place(0, 0, mScrollArea, 6, 3); - place(0, 3, mTextField, 6); - place(0, 4, mResetButton, 2); - place(2, 4, mClearButton, 2); - place(4, 4, mButton, 2); - } -} - -void NpcDialog::placeIntInputControls() -{ - if (mShowAvatar) - { - place(0, 0, mPlayerBox); - place(1, 0, mScrollArea, 6, 3); - place(1, 3, mMinusButton, 1); - place(2, 3, mIntField, 4); - place(6, 3, mPlusButton, 1); - place(0, 4, mResetButton, 2); - place(3, 4, mClearButton, 2); - place(5, 4, mButton, 2); - } - else - { - place(0, 0, mScrollArea, 6, 3); - place(0, 3, mMinusButton, 1); - place(1, 3, mIntField, 4); - place(5, 3, mPlusButton, 1); - place(0, 4, mResetButton, 2); - place(2, 4, mClearButton, 2); - place(4, 4, mButton, 2); - } -} - -void NpcDialog::placeItemInputControls() -{ - if (mShowAvatar) - { - place(0, 0, mPlayerBox); - place(1, 0, mScrollArea, 6, 3); - place(0, 3, mItemScrollArea, 7, 3); - place(1, 6, mButton3, 2); - place(3, 6, mClearButton, 2); - place(5, 6, mButton, 2); - } - else - { - place(0, 0, mScrollArea, 6, 3); - place(0, 3, mItemScrollArea, 6, 3); - place(0, 6, mButton3, 2); - place(2, 6, mClearButton, 2); - place(4, 6, mButton, 2); - } -} - -void NpcDialog::buildLayout() -{ - clearLayout(); - - if (mActionState != NPC_ACTION_INPUT) - { - if (mActionState == NPC_ACTION_WAIT) - mButton->setCaption(CAPTION_WAITING); - else if (mActionState == NPC_ACTION_NEXT) - mButton->setCaption(CAPTION_NEXT); - else if (mActionState == NPC_ACTION_CLOSE) - mButton->setCaption(CAPTION_CLOSE); - placeNormalControls(); - } - else if (mInputState != NPC_INPUT_NONE) - { - mButton->setCaption(CAPTION_SUBMIT); - switch (mInputState) - { - case NPC_INPUT_LIST: - placeMenuControls(); - mItemList->setSelected(-1); - break; - - case NPC_INPUT_STRING: - placeTextInputControls(); - break; - - case NPC_INPUT_INTEGER: - placeIntInputControls(); - break; - - case NPC_INPUT_ITEM: - placeItemInputControls(); - break; - - case NPC_INPUT_NONE: - default: - break; - } - } - - Layout &layout = getLayout(); - layout.setRowHeight(1, Layout::AUTO_SET); - redraw(); - mScrollArea->setVerticalScrollAmount(mScrollArea->getVerticalMaxScroll()); -} - -void NpcDialog::saveCamera() -{ - if (!viewport || mCameraMode >= 0) - return; - - mCameraMode = viewport->getCameraMode(); - mCameraX = viewport->getCameraRelativeX(); - mCameraY = viewport->getCameraRelativeY(); -} - -void NpcDialog::restoreCamera() -{ - if (!viewport || mCameraMode == -1) - return; - - if (!mCameraMode) - { - if (viewport->getCameraMode() != mCameraMode) - viewport->toggleCameraMode(); - } - else - { - if (viewport->getCameraMode() != mCameraMode) - viewport->toggleCameraMode(); - viewport->setCameraRelativeX(mCameraX); - viewport->setCameraRelativeY(mCameraY); - } - mCameraMode = -1; -} - -void NpcDialog::showAvatar(const uint16_t avatarId) -{ - const bool needShow = (avatarId != 0); - if (needShow) - { - delete mAvatarBeing; - mAvatarBeing = new Being(0, ActorSprite::AVATAR, avatarId, nullptr); - mPlayerBox->setPlayer(mAvatarBeing); - if (!mAvatarBeing->empty()) - { - mAvatarBeing->logic(); - const BeingInfo *const info = AvatarDB::get(avatarId); - const int pad2 = 2 * mPadding; - int width = 0; - if (info) - { - width = info->getWidth(); - mPlayerBox->setWidth(width + pad2); - mPlayerBox->setHeight(info->getHeight() + pad2); - } - const Sprite *const sprite = mAvatarBeing->getSprite(0); - if (sprite && !width) - { - mPlayerBox->setWidth(sprite->getWidth() + pad2); - mPlayerBox->setHeight(sprite->getHeight() + pad2); - } - } - } - else - { - delete mAvatarBeing; - mAvatarBeing = nullptr; - mPlayerBox->setPlayer(nullptr); - } - if (needShow != mShowAvatar) - { - mShowAvatar = needShow; - buildLayout(); - } - else - { - mShowAvatar = needShow; - } -} - -void NpcDialog::setAvatarDirection(const uint8_t direction) -{ - Being *const being = mPlayerBox->getBeing(); - if (being) - being->setDirection(direction); -} - -void NpcDialog::setAvatarAction(const int actionId) -{ - Being *const being = mPlayerBox->getBeing(); - if (being) - being->setAction(static_cast(actionId)); -} - -void NpcDialog::logic() -{ - BLOCK_START("NpcDialog::logic") - Window::logic(); - if (mShowAvatar && mAvatarBeing) - { - mAvatarBeing->logic(); - if (mPlayerBox->getWidth() < static_cast(3 * getPadding())) - { - const Sprite *const sprite = mAvatarBeing->getSprite(0); - if (sprite) - { - mPlayerBox->setWidth(sprite->getWidth() + 2 * getPadding()); - mPlayerBox->setHeight(sprite->getHeight() + 2 * getPadding()); - buildLayout(); - } - } - } - BLOCK_END("NpcDialog::logic") -} - -void NpcDialog::clearRows() -{ - mTextBox->clearRows(); -} - -void NpcDialog::clearDialogs() -{ - NpcDialogs::iterator it = mNpcDialogs.begin(); - const NpcDialogs::iterator it_end = mNpcDialogs.end(); - while (it != it_end) - { - delete (*it).second; - ++ it; - } - mNpcDialogs.clear(); -} - -void NpcDialog::mousePressed(gcn::MouseEvent &event) -{ - Window::mousePressed(event); - if (event.getButton() == gcn::MouseEvent::RIGHT - && event.getSource() == mTextBox) - { - if (viewport) - viewport->showNpcDialogPopup(mNpcId); - } -} - -void NpcDialog::copyToClipboard(const int npcId, const int x, const int y) -{ - NpcDialogs::iterator it = mNpcDialogs.find(npcId); - if (it != mNpcDialogs.end()) - { - const BrowserBox *const text = (*it).second->mTextBox; - if (!text) - return; - - std::string str = text->getTextAtPos(x, y); - sendBuffer(str); - } -} diff --git a/src/gui/npcdialog.h b/src/gui/npcdialog.h deleted file mode 100644 index d67407ac9..000000000 --- a/src/gui/npcdialog.h +++ /dev/null @@ -1,301 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_NPCDIALOG_H -#define GUI_NPCDIALOG_H - -#include "configlistener.h" - -#include "gui/widgets/extendedlistmodel.h" -#include "gui/widgets/window.h" - -#include "utils/stringvector.h" - -#include - -#include - -class Being; -class Button; -class BrowserBox; -class ExtendedListBox; -class ItemLinkHandler; -class Inventory; -class IntTextField; -class ItemContainer; -class NpcDialog; -class PlayerBox; -class ScrollArea; -class TextBox; -class TextField; - -typedef std::map NpcDialogs; - -/** - * The npc dialog. - * - * \ingroup Interface - */ -class NpcDialog final : public Window, - public gcn::ActionListener, - public ExtendedListModel, - public ConfigListener -{ - public: - /** - * Constructor. - * - * @see Window::Window - */ - explicit NpcDialog(const int npcId); - - A_DELETE_COPY(NpcDialog) - - ~NpcDialog(); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - /** - * Sets the text shows in the dialog. - * - * @param string The new text. - */ -// void setText(const std::string &string); - - /** - * Adds the text to the text shows in the dialog. Also adds a newline - * to the end. - * - * @param string The text to add. - */ - void addText(const std::string &string, const bool save = true); - - /** - * When called, the widget will show a "Next" button. - */ - void showNextButton(); - - /** - * When called, the widget will show a "Close" button and will close - * the dialog when clicked. - */ - void showCloseButton(); - - /** - * Notifies the server that client has performed a next action. - */ - void nextDialog(); - - /** - * Notifies the server that the client has performed a close action. - */ - void closeDialog(); - - /** - * Returns the number of items in the choices list. - */ - int getNumberOfElements() override A_WARN_UNUSED; - - /** - * Returns the name of item number i of the choices list. - */ - std::string getElementAt(int i) override A_WARN_UNUSED; - - /** - * Returns the image of item number i of the choices list. - */ - const Image *getImageAt(int i) override A_WARN_UNUSED; - - /** - * Makes this dialog request a choice selection from the user. - */ - void choiceRequest(); - - /** - * Adds a choice to the list box. - */ - void addChoice(const std::string &); - - /** - * Fills the options list for an NPC dialog. - * - * @param itemString A string with the options separated with colons. - */ - void parseListItems(const std::string &itemString); - - /** - * Requests a text string from the user. - */ - void textRequest(const std::string &defaultText = ""); - - bool isInputFocused() const A_WARN_UNUSED; - - bool isTextInputFocused() const A_WARN_UNUSED; - - static bool isAnyInputFocused() A_WARN_UNUSED; - - /** - * Requests a interger from the user. - */ - void integerRequest(const int defaultValue = 0, const int min = 0, - const int max = 2147483647); - - void itemRequest(); - - void move(const int amount); - - void setVisible(bool visible) override; - - void optionChanged(const std::string &name) override; - - /** - * Returns true if any instances exist. - */ - static bool isActive() A_WARN_UNUSED - { return !instances.empty(); } - - /** - * Returns the first active instance. Useful for pushing user - * interaction. - */ - static NpcDialog *getActive() A_WARN_UNUSED; - - /** - * Closes all instances. - */ - static void closeAll(); - - /** - * Closes all instances and destroy also net handler dialogs. - */ - static void destroyAll(); - - void saveCamera(); - - void restoreCamera(); - - void refocus(); - - void showAvatar(const uint16_t avatarId); - - void setAvatarDirection(const uint8_t direction); - - void setAvatarAction(const int actionId); - - void logic() override; - - void clearRows(); - - void mousePressed(gcn::MouseEvent &event); - - static void copyToClipboard(const int npcId, const int x, const int y); - - static NpcDialogs mNpcDialogs; - - static void clearDialogs(); - - private: - typedef std::list DialogList; - static DialogList instances; - - void buildLayout(); - - void placeNormalControls(); - - void placeMenuControls(); - - void placeTextInputControls(); - - void placeIntInputControls(); - - void placeItemInputControls(); - - int mNpcId; - - int mDefaultInt; - std::string mDefaultString; - - // Used for the main input area - BrowserBox *mTextBox; - ScrollArea *mScrollArea; - std::string mText; - std::string mNewText; - - // Used for choice input - ExtendedListBox *mItemList; - ScrollArea *mListScrollArea; - StringVect mItems; - std::vector mImages; - ItemLinkHandler *mItemLinkHandler; - - // Used for string and integer input - TextField *mTextField; - IntTextField *mIntField; - Button *mPlusButton; - Button *mMinusButton; - Button *mClearButton; - - // Used for the button - Button *mButton; - Button *mButton2; - Button *mButton3; - - // Will reset the text and integer input to the provided default - Button *mResetButton; - - Inventory *mInventory; - ItemContainer *mItemContainer; - ScrollArea *mItemScrollArea; - - enum NpcInputState - { - NPC_INPUT_NONE = 0, - NPC_INPUT_LIST, - NPC_INPUT_STRING, - NPC_INPUT_INTEGER, - NPC_INPUT_ITEM - }; - - enum NpcActionState - { - NPC_ACTION_WAIT = 0, - NPC_ACTION_NEXT, - NPC_ACTION_INPUT, - NPC_ACTION_CLOSE - }; - - NpcInputState mInputState; - NpcActionState mActionState; - int mLastNextTime; - int mCameraMode; - int mCameraX; - int mCameraY; - PlayerBox *mPlayerBox; - Being *mAvatarBeing; - bool mShowAvatar; - bool mLogInteraction; -}; - -#endif // GUI_NPCDIALOG_H diff --git a/src/gui/npcpostdialog.cpp b/src/gui/npcpostdialog.cpp deleted file mode 100644 index c76869980..000000000 --- a/src/gui/npcpostdialog.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2008-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/npcpostdialog.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/chattab.h" -#include "gui/widgets/label.h" -#include "gui/widgets/textbox.h" -#include "gui/widgets/textfield.h" -#include "gui/widgets/scrollarea.h" - -#include "net/net.h" -#include "net/npchandler.h" - -#include "utils/gettext.h" - -#include "debug.h" - -NpcPostDialog::DialogList NpcPostDialog::instances; - -NpcPostDialog::NpcPostDialog(const int npcId): - // TRANSLATORS: npc post dialog caption - Window(_("NPC"), false, nullptr, "npcpost.xml"), - gcn::ActionListener(), - mNpcId(npcId), - mText(new TextBox(this)), - mSender(new TextField(this)) -{ - setContentSize(400, 180); - - // create text field for receiver - // TRANSLATORS: label in npc post dialog - Label *const senderText = new Label(this, _("To:")); - senderText->setPosition(5, 5); - mSender->setPosition(senderText->getWidth() + 5, 5); - mSender->setWidth(65); - - // create button for sending - // TRANSLATORS: button in npc post dialog - Button *const sendButton = new Button(this, _("Send"), "send", this); - sendButton->setPosition(400 - sendButton->getWidth(), - 170 - sendButton->getHeight()); - // TRANSLATORS: button in npc post dialog - Button *const cancelButton = new Button(this, _("Cancel"), "cancel", this); - cancelButton->setPosition(sendButton->getX() - - (cancelButton->getWidth() + 2), sendButton->getY()); - - // create textfield for letter - mText->setHeight(400 - (mSender->getHeight() + sendButton->getHeight())); - mText->setEditable(true); - - // create scroll box for letter text - ScrollArea *const scrollArea = new ScrollArea(mText); - scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - scrollArea->setDimension(gcn::Rectangle( - 5, mSender->getHeight() + 5, - 380, 140 - (mSender->getHeight() + sendButton->getHeight()))); - - add(senderText); - add(mSender); - add(scrollArea); - add(sendButton); - add(cancelButton); - - setLocationRelativeTo(getParent()); - - instances.push_back(this); - setVisible(true); - enableVisibleSound(true); -} - -NpcPostDialog::~NpcPostDialog() -{ - instances.remove(this); -} - -void NpcPostDialog::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "send") - { - if (mSender->getText().empty() || mText->getText().empty()) - { - if (localChatTab) - { - // TRANSLATORS: npc post message error - localChatTab->chatLog(_("Failed to send as sender or letter " - "invalid.")); - } - } - else - { - Net::getNpcHandler()->sendLetter(mNpcId, mSender->getText(), - mText->getText()); - } - setVisible(false); - } - else if (eventId == "cancel") - { - setVisible(false); - } -} - -void NpcPostDialog::setVisible(bool visible) -{ - Window::setVisible(visible); - - if (!visible) - scheduleDelete(); -} - -void NpcPostDialog::closeAll() -{ - FOR_EACH (DialogList::const_iterator, it, instances) - (*it)->close(); -} diff --git a/src/gui/npcpostdialog.h b/src/gui/npcpostdialog.h deleted file mode 100644 index d9c31d6fd..000000000 --- a/src/gui/npcpostdialog.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2008-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_NPCPOSTDIALOG_H -#define GUI_NPCPOSTDIALOG_H - -#include "gui/widgets/window.h" - -#include - -class TextBox; -class TextField; - -class NpcPostDialog final : public Window, - public gcn::ActionListener -{ - public: - /** - * Constructor - */ - explicit NpcPostDialog(const int npcId); - - A_DELETE_COPY(NpcPostDialog) - - ~NpcPostDialog(); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - void setVisible(bool visible) override; - - /** - * Returns true if any instances exist. - */ - static bool isActive() A_WARN_UNUSED - { return !instances.empty(); } - - /** - * Closes all instances. - */ - static void closeAll(); - - private: - typedef std::list DialogList; - static DialogList instances; - - int mNpcId; - - TextBox *mText; - TextField *mSender; -}; - -#endif // GUI_NPCPOSTDIALOG_H diff --git a/src/gui/okdialog.cpp b/src/gui/okdialog.cpp deleted file mode 100644 index 0bb08b3b1..000000000 --- a/src/gui/okdialog.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/okdialog.h" - -#include "soundconsts.h" -#include "soundmanager.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/textbox.h" - -#include "utils/gettext.h" - -#include - -#include "debug.h" - -OkDialog::OkDialog(const std::string &title, const std::string &msg, - const int soundEvent, const bool modal, - const bool showCenter, Window *const parent, - const int minWidth) : - Window(title, modal, parent, "ok.xml"), - gcn::ActionListener(), - mTextBox(new TextBox(this)) -{ - mTextBox->setEditable(false); - mTextBox->setOpaque(false); - mTextBox->setTextWrapped(msg, minWidth); - - // TRANSLATORS: ok dialog button - Button *const okButton = new Button(this, _("OK"), "ok", this); - - int width = getFont()->getWidth(title); - if (width < mTextBox->getMinWidth()) - width = mTextBox->getMinWidth(); - if (width < okButton->getWidth()) - width = okButton->getWidth(); - - if (mTextBox->getWidth() > width) - width = mTextBox->getWidth(); - if (okButton->getWidth() > width) - width = okButton->getWidth(); - setContentSize(width, mTextBox->getHeight() + okButton->getHeight() - + getOption("buttonPadding", 8)); - mTextBox->setPosition((width - mTextBox->getWidth()) / 2, 0); - okButton->setPosition((width - okButton->getWidth()) / 2, - mTextBox->getHeight() + getOption("buttonPadding", 8)); - - add(mTextBox); - add(okButton); - - if (showCenter) - center(); - else - centerHorisontally(); - setVisible(true); - okButton->requestFocus(); - - if (soundEvent == DIALOG_OK) - soundManager.playGuiSound(SOUND_INFO); - else if (soundEvent == DIALOG_ERROR) - soundManager.playGuiSound(SOUND_ERROR); -} - -void OkDialog::action(const gcn::ActionEvent &event) -{ - setActionEventId(event.getId()); - distributeActionEvent(); - scheduleDelete(); -} diff --git a/src/gui/okdialog.h b/src/gui/okdialog.h deleted file mode 100644 index 851590595..000000000 --- a/src/gui/okdialog.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_OKDIALOG_H -#define GUI_OKDIALOG_H - -#include "localconsts.h" - -#include "gui/widgets/window.h" - -#include - -class TextBox; - -enum -{ - DIALOG_OK = 0, - DIALOG_ERROR, - DIALOG_SILENCE -}; - -/** - * An 'Ok' button dialog. - * - * \ingroup GUI - */ -class OkDialog final : public Window, - public gcn::ActionListener -{ - public: - /** - * Constructor. - * - * @see Window::Window - */ - OkDialog(const std::string &title, const std::string &msg, - const int soundEvent = DIALOG_OK, const bool modal = true, - const bool showCenter = true, Window *const parent = nullptr, - const int minWidth = 260); - - A_DELETE_COPY(OkDialog) - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - private: - TextBox *mTextBox; -}; - -#endif // GUI_OKDIALOG_H diff --git a/src/gui/outfitwindow.cpp b/src/gui/outfitwindow.cpp deleted file mode 100644 index 504c8bf49..000000000 --- a/src/gui/outfitwindow.cpp +++ /dev/null @@ -1,662 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2007-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/outfitwindow.h" - -#include "configuration.h" -#include "dragdrop.h" -#include "emoteshortcut.h" -#include "game.h" -#include "inventory.h" -#include "item.h" - -#include "being/playerinfo.h" - -#include "input/inputmanager.h" - -#include "gui/viewport.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/checkbox.h" -#include "gui/widgets/label.h" -#include "gui/widgets/layout.h" - -#include "resources/image.h" - -#include "utils/gettext.h" - -#include "net/inventoryhandler.h" -#include "net/net.h" - -#include - -#include "debug.h" - -float OutfitWindow::mAlpha = 1.0; - -OutfitWindow::OutfitWindow(): - // TRANSLATORS: outfits window name - Window(_("Outfits"), false, nullptr, "outfits.xml"), - gcn::ActionListener(), - // TRANSLATORS: outfits window button - mPreviousButton(new Button(this, _("<"), "previous", this)), - // TRANSLATORS: outfits window button - mNextButton(new Button(this, _(">"), "next", this)), - // TRANSLATORS: outfits window button - mEquipButtom(new Button(this, _("Equip"), "equip", this)), - // TRANSLATORS: outfits window label - mCurrentLabel(new Label(this, strprintf(_("Outfit: %d"), 1))), - // TRANSLATORS: outfits window checkbox - mUnequipCheck(new CheckBox(this, _("Unequip first"), - serverConfig.getValueBool("OutfitUnequip0", true))), - // TRANSLATORS: outfits window checkbox - mAwayOutfitCheck(new CheckBox(this, _("Away outfit"), - serverConfig.getValue("OutfitAwayIndex", OUTFITS_COUNT - 1))), - mCurrentOutfit(0), - // TRANSLATORS: outfits window label - mKeyLabel(new Label(this, strprintf(_("Key: %s"), - keyName(mCurrentOutfit).c_str()))), - mBoxWidth(33), - mBoxHeight(33), - mGridWidth(4), - mGridHeight(4), - mItems(), - mAwayOutfit(0), - mBorderColor(getThemeColor(Theme::BORDER, 64)), - mBackgroundColor(getThemeColor(Theme::BACKGROUND, 32)), - mItemColors(), - mItemClicked(false), - mItemsUnequip() -{ - setWindowName("Outfits"); - setResizable(true); - setCloseButton(true); - setStickyButtonLock(true); - - setDefaultSize(250, 400, 150, 290); - setMinWidth(145); - setMinHeight(220); - - mCurrentLabel->setAlignment(gcn::Graphics::CENTER); - mKeyLabel->setAlignment(gcn::Graphics::CENTER); - - mUnequipCheck->setActionEventId("unequip"); - mUnequipCheck->addActionListener(this); - - mAwayOutfitCheck->setActionEventId("away"); - mAwayOutfitCheck->addActionListener(this); - - place(1, 3, mEquipButtom, 2); - place(0, 4, mKeyLabel, 4); - place(0, 5, mPreviousButton, 1); - place(1, 5, mCurrentLabel, 2); - place(3, 5, mNextButton, 1); - place(0, 6, mUnequipCheck, 4); - place(0, 7, mAwayOutfitCheck, 4); - - Layout &layout = getLayout(); - layout.setRowHeight(0, Layout::AUTO_SET); - layout.setColWidth(4, Layout::CENTER); - - loadWindowState(); - - enableVisibleSound(true); - load(); -} - -OutfitWindow::~OutfitWindow() -{ - save(); -} - -void OutfitWindow::load(const bool oldConfig) -{ - const Configuration *cfg; - if (oldConfig) - cfg = &config; - else - cfg = &serverConfig; - - memset(mItems, -1, sizeof(mItems)); - memset(mItemColors, 1, sizeof(mItemColors)); - - for (unsigned o = 0; o < OUTFITS_COUNT; o++) - { - std::string outfit = cfg->getValue("Outfit" + toString(o), "-1"); - std::string buf; - std::stringstream ss(outfit); - - std::vector tokens; - - while (ss >> buf) - tokens.push_back(atoi(buf.c_str())); - - for (size_t i = 0, sz = tokens.size(); - i < sz && i < OUTFIT_ITEM_COUNT; i++) - { - mItems[o][i] = tokens[i]; - } - - outfit = cfg->getValue("OutfitColor" + toString(o), "1"); - std::stringstream ss2(outfit); - - tokens.clear(); - - std::vector tokens2; - while (ss2 >> buf) - tokens2.push_back(static_cast(atoi(buf.c_str()))); - - for (size_t i = 0, sz = tokens2.size(); - i < sz && i < OUTFIT_ITEM_COUNT; i++) - { - mItemColors[o][i] = tokens2[i]; - } - - mItemsUnequip[o] = cfg->getValueBool("OutfitUnequip" + toString(o), - true); - } - mAwayOutfit = cfg->getValue("OutfitAwayIndex", OUTFITS_COUNT - 1); - if (mAwayOutfit >= static_cast(OUTFITS_COUNT)) - mAwayOutfit = static_cast(OUTFITS_COUNT) - 1; - - if (mAwayOutfitCheck) - mAwayOutfitCheck->setSelected(mAwayOutfit == mCurrentOutfit); -} - -void OutfitWindow::save() const -{ - std::string outfitStr; - std::string outfitColorsStr; - for (unsigned o = 0; o < OUTFITS_COUNT; o++) - { - bool good = false; - for (unsigned i = 0; i < OUTFIT_ITEM_COUNT; i++) - { - const int val = mItems[o][i]; - const int res = val ? val : -1; - if (res != -1) - good = true; - outfitStr.append(toString(res)); - if (i < OUTFIT_ITEM_COUNT - 1) - outfitStr.append(" "); - outfitColorsStr.append(toString(static_cast( - mItemColors[o][i]))); - if (i < OUTFIT_ITEM_COUNT - 1) - outfitColorsStr.append(" "); - } - if (good) - { - serverConfig.setValue("Outfit" + toString(o), outfitStr); - serverConfig.setValue("OutfitColor" + toString(o), - outfitColorsStr); - } - else - { - serverConfig.deleteKey("Outfit" + toString(o)); - serverConfig.deleteKey("OutfitColor" + toString(o)); - } - - if (mItemsUnequip[o]) - { - serverConfig.deleteKey("OutfitUnequip" + toString(o)); - } - else - { - serverConfig.setValue("OutfitUnequip" + toString(o), - mItemsUnequip[o]); - } - outfitStr.clear(); - outfitColorsStr.clear(); - } - serverConfig.setValue("OutfitAwayIndex", mAwayOutfit); -} - -void OutfitWindow::action(const gcn::ActionEvent &event) -{ - const std::string eventId = event.getId(); - if (eventId == "next") - { - next(); - } - else if (eventId == "previous") - { - previous(); - } - else if (eventId == "unequip") - { - if (mCurrentOutfit >= 0 && mCurrentOutfit < static_cast( - OUTFITS_COUNT)) - { - mItemsUnequip[mCurrentOutfit] = mUnequipCheck->isSelected(); - } - } - else if (eventId == "equip") - { - wearOutfit(mCurrentOutfit); - if (Game::instance()) - Game::instance()->setValidSpeed(); - } - else if (eventId == "away") - { - mAwayOutfit = mCurrentOutfit; - if (!mAwayOutfitCheck->isSelected()) - mAwayOutfitCheck->setSelected(true); - } -} - -void OutfitWindow::wearOutfit(const int outfit, const bool unwearEmpty, - const bool select) -{ - bool isEmpty = true; - - if (outfit < 0 || outfit > static_cast(OUTFITS_COUNT)) - return; - - for (unsigned i = 0; i < OUTFIT_ITEM_COUNT; i++) - { - const Item *const item = PlayerInfo::getInventory()->findItem( - mItems[outfit][i], mItemColors[outfit][i]); - if (item && !item->isEquipped() && item->getQuantity()) - { - if (item->isEquipment()) - { - Net::getInventoryHandler()->equipItem(item); - isEmpty = false; - } - } - } - - if ((!isEmpty || unwearEmpty) && outfit < static_cast(OUTFITS_COUNT) - && mItemsUnequip[outfit]) - { - unequipNotInOutfit(outfit); - } - if (select) - { - mCurrentOutfit = outfit; - showCurrentOutfit(); - } -} - -void OutfitWindow::copyOutfit(const int outfit) -{ - copyOutfit(outfit, mCurrentOutfit); -} - -void OutfitWindow::copyOutfit(const int src, const int dst) -{ - if (src < 0 || src > static_cast(OUTFITS_COUNT) - || dst < 0 || dst > static_cast(OUTFITS_COUNT)) - { - return; - } - - for (unsigned int i = 0; i < OUTFIT_ITEM_COUNT; i++) - mItems[dst][i] = mItems[src][i]; -} - -void OutfitWindow::draw(gcn::Graphics *graphics) -{ - BLOCK_START("OutfitWindow::draw") - Window::draw(graphics); - Graphics *const g = static_cast(graphics); - - if (mCurrentOutfit < 0 || mCurrentOutfit - >= static_cast(OUTFITS_COUNT)) - { - return; - } - - for (unsigned int i = 0; i < OUTFIT_ITEM_COUNT; i++) - { - const int itemX = mPadding + ((i % mGridWidth) * mBoxWidth); - const int itemY = mPadding + mTitleBarHeight - + ((i / mGridWidth) * mBoxHeight); - - graphics->setColor(mBorderColor); - graphics->drawRectangle(gcn::Rectangle(itemX, itemY, 32, 32)); - graphics->setColor(mBackgroundColor); - graphics->fillRectangle(gcn::Rectangle(itemX, itemY, 32, 32)); - - if (mItems[mCurrentOutfit][i] < 0) - continue; - - bool foundItem = false; - const Inventory *const inv = PlayerInfo::getInventory(); - if (inv) - { - const Item *const item = inv->findItem(mItems[mCurrentOutfit][i], - mItemColors[mCurrentOutfit][i]); - if (item) - { - // Draw item icon. - const Image *const image = item->getImage(); - if (image) - { - g->drawImage(image, itemX, itemY); - foundItem = true; - } - } - } - if (!foundItem) - { - Image *const image = Item::getImage(mItems[mCurrentOutfit][i], - mItemColors[mCurrentOutfit][i]); - if (image) - { - g->drawImage(image, itemX, itemY); - image->decRef(); - } - } - } - BLOCK_END("OutfitWindow::draw") -} - - -void OutfitWindow::mouseDragged(gcn::MouseEvent &event) -{ - if (event.getButton() == gcn::MouseEvent::LEFT) - { - if (dragDrop.isEmpty() && mItemClicked) - { - if (mCurrentOutfit < 0 || mCurrentOutfit - >= static_cast(OUTFITS_COUNT)) - { - Window::mouseDragged(event); - return; - } - - const int index = getIndexFromGrid(event.getX(), event.getY()); - if (index == -1) - { - Window::mouseDragged(event); - return; - } - const int itemId = mItems[mCurrentOutfit][index]; - const unsigned char itemColor = mItemColors[mCurrentOutfit][index]; - if (itemId < 0) - { - Window::mouseDragged(event); - return; - } - mMoved = false; - event.consume(); - const Inventory *const inv = PlayerInfo::getInventory(); - if (inv) - { - Item *const item = inv->findItem(itemId, itemColor); - if (item) - dragDrop.dragItem(item, DRAGDROP_SOURCE_OUTFIT); - else - dragDrop.clear(); - mItems[mCurrentOutfit][index] = -1; - } - } - } - Window::mouseDragged(event); -} - -void OutfitWindow::mousePressed(gcn::MouseEvent &event) -{ - const int index = getIndexFromGrid(event.getX(), event.getY()); - if (index == -1) - { - if (event.getButton() == gcn::MouseEvent::RIGHT && viewport) - { - viewport->showOutfitsPopup(); - event.consume(); - } - else - { - Window::mousePressed(event); - } - return; - } - mMoved = false; - event.consume(); - - if (mItems[mCurrentOutfit][index] > 0) - { - mItemClicked = true; - } - else - { - if (dragDrop.isSelected()) - { - mItems[mCurrentOutfit][index] = dragDrop.getSelected(); - mItemColors[mCurrentOutfit][index] = dragDrop.getSelectedColor(); - dragDrop.deselect(); - } - } - - Window::mousePressed(event); -} - -void OutfitWindow::mouseReleased(gcn::MouseEvent &event) -{ - if (event.getButton() == gcn::MouseEvent::LEFT) - { - if (mCurrentOutfit < 0 || mCurrentOutfit - >= static_cast(OUTFITS_COUNT)) - { - return; - } - const int index = getIndexFromGrid(event.getX(), event.getY()); - if (index == -1) - { - dragDrop.clear(); - Window::mouseReleased(event); - return; - } - mMoved = false; - event.consume(); - if (!dragDrop.isEmpty()) - { - if (dragDrop.isSourceItemContainer()) - { - mItems[mCurrentOutfit][index] = dragDrop.getItem(); - mItemColors[mCurrentOutfit][index] = dragDrop.getItemColor(); - dragDrop.clear(); - dragDrop.deselect(); - } - } - if (mItemClicked) - mItemClicked = false; - } - Window::mouseReleased(event); -} - -int OutfitWindow::getIndexFromGrid(const int pointX, const int pointY) const -{ - const gcn::Rectangle tRect = gcn::Rectangle(mPadding, mTitleBarHeight, - mGridWidth * mBoxWidth, mGridHeight * mBoxHeight); - if (!tRect.isPointInRect(pointX, pointY)) - return -1; - const int index = (((pointY - mTitleBarHeight) / mBoxHeight) * mGridWidth) - + (pointX - mPadding) / mBoxWidth; - if (index >= static_cast(OUTFIT_ITEM_COUNT) || index < 0) - return -1; - return index; -} - -void OutfitWindow::unequipNotInOutfit(const int outfit) const -{ - // here we think that outfit is correct index - - const Inventory *const inventory = PlayerInfo::getInventory(); - if (!inventory) - return; - - const unsigned int invSize = inventory->getSize(); - for (unsigned i = 0; i < invSize; i++) - { - const Item *const item = inventory->getItem(i); - if (item && item->isEquipped()) - { - bool found = false; - for (unsigned f = 0; f < OUTFIT_ITEM_COUNT; f++) - { - if (item->getId() == mItems[outfit][f]) - { - found = true; - break; - } - } - if (!found) - Net::getInventoryHandler()->unequipItem(item); - } - } -} - -std::string OutfitWindow::keyName(const int number) const -{ - if (number < 0 || number >= SHORTCUT_EMOTES) - return ""; - return inputManager.getKeyStringLong(static_cast( - Input::KEY_EMOTE_1) + number); -} - -void OutfitWindow::next() -{ - if (mCurrentOutfit < (static_cast(OUTFITS_COUNT) - 1)) - mCurrentOutfit++; - else - mCurrentOutfit = 0; - showCurrentOutfit(); -} - -void OutfitWindow::previous() -{ - if (mCurrentOutfit > 0) - mCurrentOutfit--; - else - mCurrentOutfit = OUTFITS_COUNT - 1; - showCurrentOutfit(); -} - -void OutfitWindow::showCurrentOutfit() -{ - // TRANSLATORS: outfits window label - mCurrentLabel->setCaption(strprintf(_("Outfit: %d"), mCurrentOutfit + 1)); - if (mCurrentOutfit < static_cast(OUTFITS_COUNT)) - mUnequipCheck->setSelected(mItemsUnequip[mCurrentOutfit]); - else - mUnequipCheck->setSelected(false); - // TRANSLATORS: outfits window label - mKeyLabel->setCaption(strprintf(_("Key: %s"), - keyName(mCurrentOutfit).c_str())); - mAwayOutfitCheck->setSelected(mAwayOutfit == mCurrentOutfit); -} - -void OutfitWindow::wearNextOutfit(const bool all) -{ - next(); - if (!all && mCurrentOutfit >= 0 && mCurrentOutfit - < static_cast(OUTFITS_COUNT)) - { - bool fromStart = false; - while (!mItemsUnequip[mCurrentOutfit]) - { - next(); - if (mCurrentOutfit == 0) - { - if (!fromStart) - fromStart = true; - else - return; - } - } - } - wearOutfit(mCurrentOutfit); -} - -void OutfitWindow::wearPreviousOutfit(const bool all) -{ - previous(); - if (!all && mCurrentOutfit >= 0 && mCurrentOutfit - < static_cast(OUTFITS_COUNT)) - { - bool fromStart = false; - while (!mItemsUnequip[mCurrentOutfit]) - { - previous(); - if (mCurrentOutfit == 0) - { - if (!fromStart) - fromStart = true; - else - return; - } - } - } - wearOutfit(mCurrentOutfit); -} - -void OutfitWindow::copyFromEquiped() -{ - copyFromEquiped(mCurrentOutfit); -} - -void OutfitWindow::copyFromEquiped(const int dst) -{ - const Inventory *const inventory = PlayerInfo::getInventory(); - if (!inventory) - return; - - int outfitCell = 0; - for (unsigned i = 0, sz = inventory->getSize(); i < sz; i++) - { - const Item *const item = inventory->getItem(i); - if (item && item->isEquipped()) - { - mItems[dst][outfitCell] = item->getId(); - mItemColors[dst][outfitCell++] = item->getColor(); - if (outfitCell >= static_cast(OUTFIT_ITEM_COUNT)) - break; - } - } -} - -void OutfitWindow::wearAwayOutfit() -{ - copyFromEquiped(OUTFITS_COUNT); - wearOutfit(mAwayOutfit, false); -} - -void OutfitWindow::unwearAwayOutfit() -{ - wearOutfit(OUTFITS_COUNT); -} - -void OutfitWindow::clearCurrentOutfit() -{ - if (mCurrentOutfit < 0 || mCurrentOutfit - >= static_cast(OUTFITS_COUNT)) - { - return; - } - for (unsigned f = 0; f < OUTFIT_ITEM_COUNT; f++) - { - mItems[mCurrentOutfit][f] = -1; - mItemColors[mCurrentOutfit][f] = 1; - } -} diff --git a/src/gui/outfitwindow.h b/src/gui/outfitwindow.h deleted file mode 100644 index 5f7d32e02..000000000 --- a/src/gui/outfitwindow.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2007-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_OUTFITWINDOW_H -#define GUI_OUTFITWINDOW_H - -#include "gui/widgets/window.h" - -#include - -const unsigned int OUTFITS_COUNT = 100; -const unsigned int OUTFIT_ITEM_COUNT = 16; - -class Button; -class CheckBox; -class Label; - -class OutfitWindow final : public Window, - private gcn::ActionListener -{ - public: - /** - * Constructor. - */ - OutfitWindow(); - - A_DELETE_COPY(OutfitWindow) - - /** - * Destructor. - */ - ~OutfitWindow(); - - void action(const gcn::ActionEvent &event) override; - - void draw(gcn::Graphics *graphics) override; - - void mousePressed(gcn::MouseEvent &event) override; - - void mouseDragged(gcn::MouseEvent &event) override; - - void mouseReleased(gcn::MouseEvent &event) override; - - void load(const bool oldConfig = false); - - void wearOutfit(const int outfit, const bool unwearEmpty = true, - const bool select = false); - - void copyOutfit(const int outfit); - - void copyOutfit(const int src, const int dst); - - void copyFromEquiped(); - - void copyFromEquiped(const int dst); - - void unequipNotInOutfit(const int outfit) const; - - void next(); - - void previous(); - - void wearNextOutfit(const bool all = false); - - void wearPreviousOutfit(const bool all = false); - - void wearAwayOutfit(); - - void unwearAwayOutfit(); - - void showCurrentOutfit(); - - std::string keyName(const int number) const A_WARN_UNUSED; - - void clearCurrentOutfit(); - - private: - Button *mPreviousButton; - Button *mNextButton; - Button *mEquipButtom; - Label *mCurrentLabel; - CheckBox *mUnequipCheck; - CheckBox *mAwayOutfitCheck; - int mCurrentOutfit; - Label *mKeyLabel; - - int getIndexFromGrid(const int pointX, - const int pointY) const A_WARN_UNUSED; - void save() const; - - int mBoxWidth; - int mBoxHeight; - int mGridWidth; - int mGridHeight; - - int mItems[OUTFITS_COUNT + 1][OUTFIT_ITEM_COUNT]; - int mAwayOutfit; - - gcn::Color mBorderColor; - gcn::Color mBackgroundColor; - unsigned char mItemColors[OUTFITS_COUNT + 1][OUTFIT_ITEM_COUNT]; - bool mItemClicked; - bool mItemsUnequip[OUTFITS_COUNT]; - - static float mAlpha; -}; - -extern OutfitWindow *outfitWindow; - -#endif // GUI_OUTFITWINDOW_H diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp index fc16b7e36..62f769378 100644 --- a/src/gui/popupmenu.cpp +++ b/src/gui/popupmenu.cpp @@ -40,21 +40,22 @@ #include "input/inputmanager.h" -#include "gui/chatwindow.h" -#include "gui/equipmentwindow.h" -#include "gui/inventorywindow.h" -#include "gui/itemamountwindow.h" -#include "gui/ministatuswindow.h" -#include "gui/npcdialog.h" -#include "gui/outfitwindow.h" -#include "gui/skilldialog.h" -#include "gui/socialwindow.h" -#include "gui/textcommandeditor.h" -#include "gui/textdialog.h" -#include "gui/tradewindow.h" -#include "gui/viewport.h" +#include "gui/windows/chatwindow.h" +#include "gui/windows/equipmentwindow.h" +#include "gui/windows/inventorywindow.h" +#include "gui/windows/itemamountwindow.h" +#include "gui/windows/ministatuswindow.h" +#include "gui/windows/npcdialog.h" +#include "gui/windows/outfitwindow.h" +#include "gui/windows/skilldialog.h" +#include "gui/windows/socialwindow.h" +#include "gui/windows/textcommandeditor.h" +#include "gui/windows/textdialog.h" +#include "gui/windows/tradewindow.h" #include "gui/windowmenu.h" +#include "gui/viewport.h" + #include "gui/widgets/browserbox.h" #include "gui/widgets/chattab.h" #include "gui/widgets/progressbar.h" diff --git a/src/gui/questswindow.cpp b/src/gui/questswindow.cpp deleted file mode 100644 index e77d2bbd7..000000000 --- a/src/gui/questswindow.cpp +++ /dev/null @@ -1,567 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2012-2013 The ManaPlus developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/questswindow.h" - -#include "actorspritemanager.h" -#include "configuration.h" -#include "effectmanager.h" - -#include "being/localplayer.h" - -#include "gui/gui.h" -#include "gui/sdlfont.h" - -#include "gui/widgets/browserbox.h" -#include "gui/widgets/button.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/extendedlistbox.h" -#include "gui/widgets/extendednamesmodel.h" -#include "gui/widgets/itemlinkhandler.h" -#include "gui/widgets/scrollarea.h" - -#include "utils/dtor.h" -#include "utils/gettext.h" - -#include "utils/translation/podict.h" - -#include "debug.h" - -enum QuestType -{ - QUEST_TEXT = 0, - QUEST_NAME = 1, - QUEST_REWARD = 2 -}; - -struct QuestItemText final -{ - QuestItemText(const std::string &text0, const int type0) : - text(text0), type(type0) - { - } - - std::string text; - int type; -}; - -struct QuestItem final -{ - QuestItem() : - var(0), - name(), - group(), - incomplete(), - complete(), - texts(), - completeFlag(-1), - broken(false) - { - } - - int var; - std::string name; - std::string group; - std::set incomplete; - std::set complete; - std::vector texts; - int completeFlag; - bool broken; -}; - -class QuestsModel final : public ExtendedNamesModel -{ - public: - QuestsModel() : - ExtendedNamesModel() - { - } - - A_DELETE_COPY(QuestsModel) - - ~QuestsModel() - { } -}; - -struct QuestEffect final -{ - QuestEffect() : - map(), - var(0), - id(0), - effectId(0), - values() - { - } - - std::string map; - int var; - int id; - int effectId; - std::set values; -}; - -QuestsWindow::QuestsWindow() : - // TRANSLATORS: quests window name - Window(_("Quests"), false, nullptr, "quests.xml"), - gcn::ActionListener(), - mQuestsModel(new QuestsModel), - mQuestsListBox(new ExtendedListBox(this, - mQuestsModel, "extendedlistbox.xml")), - mQuestScrollArea(new ScrollArea(mQuestsListBox, - getOptionBool("showlistbackground"), "quests_list_background.xml")), - mItemLinkHandler(new ItemLinkHandler), - mText(new BrowserBox(this, BrowserBox::AUTO_WRAP)), - mTextScrollArea(new ScrollArea(mText, - getOptionBool("showtextbackground"), "quests_text_background.xml")), - // TRANSLATORS: quests window button - mCloseButton(new Button(this, _("Close"), "close", this)), - mVars(), - mQuests(), - mAllEffects(), - mMapEffects(), - mNpcEffects(), - mQuestLinks(), - mCompleteIcon(Theme::getImageFromThemeXml("complete_icon.xml", "")), - mIncompleteIcon(Theme::getImageFromThemeXml("incomplete_icon.xml", "")), - mNewQuestEffectId(paths.getIntValue("newQuestEffectId")), - mCompleteQuestEffectId(paths.getIntValue("completeQuestEffectId")), - mMap(nullptr) -{ - setWindowName("Quests"); - setResizable(true); - setCloseButton(true); - setStickyButtonLock(true); - setSaveVisible(true); - - setDefaultSize(400, 350, ImageRect::RIGHT); - setMinWidth(310); - setMinHeight(220); - - mQuestsListBox->setActionEventId("select"); - mQuestsListBox->addActionListener(this); - - mQuestScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - mText->setOpaque(false); - mText->setLinkHandler(mItemLinkHandler); - mTextScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - mQuestsListBox->setWidth(500); - if (gui->getNpcFont()->getHeight() < 20) - mQuestsListBox->setRowHeight(20); - else - mQuestsListBox->setRowHeight(gui->getNpcFont()->getHeight()); - - ContainerPlacer placer; - placer = getPlacer(0, 0); - - placer(0, 0, mQuestScrollArea, 4, 3).setPadding(3); - placer(4, 0, mTextScrollArea, 4, 3).setPadding(3); - placer(7, 3, mCloseButton); - - Layout &layout = getLayout(); - layout.setRowHeight(0, Layout::AUTO_SET); - - loadWindowState(); - enableVisibleSound(true); - loadXml(); -} - -QuestsWindow::~QuestsWindow() -{ - delete mQuestsModel; - mQuestsModel = nullptr; - - for (std::map >::iterator it - = mQuests.begin(), it_end = mQuests.end(); it != it_end; ++ it) - { - std::vector &quests = (*it).second; - for (std::vector::iterator it2 = quests.begin(), - it2_end = quests.end(); it2 != it2_end; ++ it2) - { - delete *it2; - } - } - delete_all(mAllEffects); - mAllEffects.clear(); - - delete mItemLinkHandler; - mItemLinkHandler = nullptr; - mQuests.clear(); - mQuestLinks.clear(); - if (mCompleteIcon) - { - mCompleteIcon->decRef(); - mCompleteIcon = nullptr; - } - if (mIncompleteIcon) - { - mIncompleteIcon->decRef(); - mIncompleteIcon = nullptr; - } -} - -void QuestsWindow::loadXml() -{ - XML::Document doc(paths.getStringValue("questsFile")); - const XmlNodePtr root = doc.rootNode(); - if (!root) - return; - - for_each_xml_child_node(varNode, root) - { - if (xmlNameEqual(varNode, "var")) - { - const int id = XML::getProperty(varNode, "id", 0); - if (id < 0) - continue; - for_each_xml_child_node(questNode, varNode) - { - if (xmlNameEqual(questNode, "quest")) - loadQuest(id, questNode); - else if (xmlNameEqual(questNode, "effect")) - loadEffect(id, questNode); - } - } - } -} - -void QuestsWindow::loadQuest(const int var, const XmlNodePtr node) -{ - QuestItem *const quest = new QuestItem(); - // TRANSLATORS: quests window quest name - quest->name = XML::langProperty(node, "name", _("unknown")); - quest->group = XML::getProperty(node, "group", ""); - std::string incompleteStr = XML::getProperty(node, "incomplete", ""); - std::string completeStr = XML::getProperty(node, "complete", ""); - if (incompleteStr.empty() && completeStr.empty()) - { - logger->log("complete flags incorrect"); - delete quest; - return; - } - splitToIntSet(quest->incomplete, incompleteStr, ','); - splitToIntSet(quest->complete, completeStr, ','); - if (quest->incomplete.empty() && quest->complete.empty()) - { - logger->log("complete flags incorrect"); - delete quest; - return; - } - if (quest->incomplete.empty() || quest->complete.empty()) - quest->broken = true; - - for_each_xml_child_node(dataNode, node) - { - if (!xmlTypeEqual(dataNode, XML_ELEMENT_NODE)) - continue; - const char *const data = reinterpret_cast( - xmlNodeGetContent(dataNode)); - if (!data) - continue; - std::string str = translator->getStr(data); - - if (xmlNameEqual(dataNode, "text")) - quest->texts.push_back(QuestItemText(str, QUEST_TEXT)); - else if (xmlNameEqual(dataNode, "name")) - quest->texts.push_back(QuestItemText(str, QUEST_NAME)); - else if (xmlNameEqual(dataNode, "reward")) - quest->texts.push_back(QuestItemText(str, QUEST_REWARD)); - } - mQuests[var].push_back(quest); -} - -void QuestsWindow::loadEffect(const int var, const XmlNodePtr node) -{ - QuestEffect *const effect = new QuestEffect; - effect->map = XML::getProperty(node, "map", ""); - effect->id = XML::getProperty(node, "npc", -1); - effect->effectId = XML::getProperty(node, "effect", -1); - const std::string values = XML::getProperty(node, "value", ""); - splitToIntSet(effect->values, values, ','); - - if (effect->map.empty() || effect->id == -1 - || effect->effectId == -1 || values.empty()) - { - delete effect; - return; - } - effect->var = var; - mAllEffects.push_back(effect); -} - -void QuestsWindow::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "select") - { - const int id = mQuestsListBox->getSelected(); - if (id < 0) - return; - showQuest(mQuestLinks[id]); - } - else if (eventId == "close") - { - setVisible(false); - } -} - -void QuestsWindow::updateQuest(const int var, const int val) -{ - mVars[var] = val; -} - -void QuestsWindow::rebuild(const bool playSound) -{ - mQuestsModel->clear(); - mQuestLinks.clear(); - StringVect &names = mQuestsModel->getNames(); - std::vector &images = mQuestsModel->getImages(); - std::vector complete; - std::vector incomplete; - std::vector hidden; - int updatedQuest = -1; - int newCompleteStatus = -1; - - for (std::map::const_iterator it = mVars.begin(), - it_end = mVars.end(); it != it_end; ++ it) - { - const int var = (*it).first; - const int val = (*it).second; - const std::vector &quests = mQuests[var]; - FOR_EACH (std::vector::const_iterator, it2, quests) - { - if (!*it2) - continue; - QuestItem *const quest = *it2; - // complete quest - if (quest->complete.find(val) != quest->complete.end()) - complete.push_back(quest); - // incomplete quest - else if (quest->incomplete.find(val) != quest->incomplete.end()) - incomplete.push_back(quest); - // hidden quest - else - hidden.push_back(quest); - } - } - - int k = 0; - - for (std::vector::const_iterator it = complete.begin(), - it_end = complete.end(); it != it_end; ++ it, k ++) - { - QuestItem *const quest = *it; - if (quest->completeFlag == 0 || (quest->broken - && quest->completeFlag == -1)) - { - updatedQuest = k; - newCompleteStatus = 1; - } - quest->completeFlag = 1; - mQuestLinks.push_back(quest); - names.push_back(quest->name); - if (mCompleteIcon) - { - mCompleteIcon->incRef(); - images.push_back(mCompleteIcon); - } - else - { - images.push_back(nullptr); - } - } - - for (std::vector::const_iterator it = incomplete.begin(), - it_end = incomplete.end(); it != it_end; ++ it, k ++) - { - QuestItem *const quest = *it; - if (quest->completeFlag == -1) - { - updatedQuest = k; - newCompleteStatus = 0; - } - quest->completeFlag = 0; - mQuestLinks.push_back(quest); - names.push_back(quest->name); - if (mIncompleteIcon) - { - mIncompleteIcon->incRef(); - images.push_back(mIncompleteIcon); - } - else - { - images.push_back(nullptr); - } - } - - FOR_EACH (std::vector::const_iterator, it, hidden) - (*it)->completeFlag = -1; - - if (updatedQuest == -1 || updatedQuest >= static_cast( - mQuestLinks.size())) - { - updatedQuest = static_cast(mQuestLinks.size() - 1); - } - if (updatedQuest >= 0) - { - mQuestsListBox->setSelected(updatedQuest); - showQuest(mQuestLinks[updatedQuest]); - if (playSound && effectManager) - { - switch (newCompleteStatus) - { - case 0: - effectManager->trigger(mNewQuestEffectId, player_node); - break; - case 1: - effectManager->trigger(mCompleteQuestEffectId, - player_node); - break; - default: - break; - } - } - } - updateEffects(); -} - -void QuestsWindow::showQuest(const QuestItem *const quest) -{ - if (!quest || !translator) - return; - - const std::vector &texts = quest->texts; - mText->clearRows(); - FOR_EACH (std::vector::const_iterator, it, texts) - { - const QuestItemText &data = *it; - switch (data.type) - { - case QUEST_TEXT: - case QUEST_REWARD: - default: - mText->addRow(translator->getStr(data.text)); - break; - case QUEST_NAME: - mText->addRow(std::string("[").append(translator->getStr( - data.text)).append("]")); - break; - } - } -} - -void QuestsWindow::setMap(const Map *const map) -{ - if (mMap != map) - { - mMap = map; - mMapEffects.clear(); - if (!mMap) - return; - - const std::string name = mMap->getProperty("shortName"); - FOR_EACH (std::vector::const_iterator, it, mAllEffects) - { - const QuestEffect *const effect = *it; - if (effect && name == effect->map) - mMapEffects.push_back(effect); - } - updateEffects(); - } -} - -void QuestsWindow::updateEffects() -{ - NpcQuestEffectMap oldNpc = mNpcEffects; - mNpcEffects.clear(); - - FOR_EACH (std::vector::const_iterator, - it, mMapEffects) - { - const QuestEffect *const effect = *it; - if (effect) - { - const std::map::const_iterator - varIt = mVars.find(effect->var); - if (varIt != mVars.end()) - { - const std::set &vals = effect->values; - if (vals.find(mVars[effect->var]) != vals.end()) - mNpcEffects[effect->id] = effect; - } - } - } - if (!actorSpriteManager) - return; - - std::set removeEffects; - std::map addEffects; - - // for old effects - FOR_EACH (NpcQuestEffectMapCIter, it, oldNpc) - { - const int id = (*it).first; - const QuestEffect *const effect = (*it).second; - - const NpcQuestEffectMapCIter itNew = mNpcEffects.find(id); - if (itNew == mNpcEffects.end()) - { // in new list no effect for this npc - removeEffects.insert(id); - } - else - { // in new list exists effect for this npc - const QuestEffect *const newEffect = (*itNew).second; - if (effect != newEffect) - { // new effects is not equal to old effect - addEffects[id] = newEffect->effectId; - removeEffects.insert(id); - } - } - } - - // for new effects - FOR_EACH (NpcQuestEffectMapCIter, it, mNpcEffects) - { - const int id = (*it).first; - const QuestEffect *const effect = (*it).second; - - const NpcQuestEffectMapCIter itNew = oldNpc.find(id); - // check if old effect was not present - if (itNew == oldNpc.end()) - addEffects[id] = effect->effectId; - } - if (!removeEffects.empty() || !addEffects.empty()) - actorSpriteManager->updateEffects(addEffects, removeEffects); -} - -void QuestsWindow::addEffect(Being *const being) -{ - if (!being) - return; - const int id = being->getSubType(); - const std::map::const_iterator - it = mNpcEffects.find(id); - if (it != mNpcEffects.end()) - { - const QuestEffect *const effect = (*it).second; - if (effect) - being->addSpecialEffect(effect->effectId); - } -} diff --git a/src/gui/questswindow.h b/src/gui/questswindow.h deleted file mode 100644 index 72fdb7bb6..000000000 --- a/src/gui/questswindow.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2012-2013 The ManaPlus developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_QUESTSWINDOW_H -#define GUI_QUESTSWINDOW_H - -#include "localconsts.h" - -#include "gui/widgets/window.h" - -#include "utils/xml.h" - -#include - -#include -#include - -class Being; -class Button; -class BrowserBox; -class ExtendedListBox; -class ItemLinkHandler; -class Map; -class ScrollArea; -class QuestsModel; - -struct QuestEffect; -struct QuestItem; - -typedef std::map NpcQuestEffectMap; -typedef NpcQuestEffectMap::const_iterator NpcQuestEffectMapCIter; - -class QuestsWindow final : public Window, - public gcn::ActionListener -{ - public: - QuestsWindow(); - - A_DELETE_COPY(QuestsWindow) - - ~QuestsWindow(); - - void action(const gcn::ActionEvent &event) override; - - void updateQuest(const int var, const int val); - - void rebuild(const bool playSound); - - void showQuest(const QuestItem *const quest); - - void setMap(const Map *const map); - - void updateEffects(); - - void addEffect(Being *const being); - - private: - void loadXml(); - - void loadQuest(const int var, const XmlNodePtr node); - - void loadEffect(const int var, const XmlNodePtr node); - - QuestsModel *mQuestsModel; - ExtendedListBox *mQuestsListBox; - ScrollArea *mQuestScrollArea; - ItemLinkHandler *mItemLinkHandler; - BrowserBox *mText; - ScrollArea *mTextScrollArea; - Button *mCloseButton; - // quest variables: var, value - std::map mVars; - // quests: var, quests - std::map > mQuests; - std::vector mAllEffects; - std::vector mMapEffects; - // npc effects for current map and values: npc, effect - NpcQuestEffectMap mNpcEffects; - std::vector mQuestLinks; - Image *mCompleteIcon; - Image *mIncompleteIcon; - int mNewQuestEffectId; - int mCompleteQuestEffectId; - const Map *mMap; -}; - -extern QuestsWindow *questsWindow; - -#endif // GUI_QUESTSWINDOW_H diff --git a/src/gui/quitdialog.cpp b/src/gui/quitdialog.cpp deleted file mode 100644 index b601fe323..000000000 --- a/src/gui/quitdialog.cpp +++ /dev/null @@ -1,256 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/quitdialog.h" - -#include "client.h" -#include "configuration.h" -#include "game.h" -#include "soundconsts.h" -#include "soundmanager.h" - -#include "input/keydata.h" -#include "input/keyevent.h" - -#include "gui/viewport.h" - -#include "gui/widgets/layout.h" -#include "gui/widgets/button.h" -#include "gui/widgets/radiobutton.h" - -#include "net/charserverhandler.h" -#include "net/gamehandler.h" -#include "net/net.h" - -#include "utils/gettext.h" -#include "utils/process.h" - -#include "debug.h" - -QuitDialog::QuitDialog(QuitDialog **const pointerToMe): - // TRANSLATORS: quit dialog name - Window(_("Quit"), true, nullptr, "quit.xml"), - gcn::ActionListener(), - gcn::KeyListener(), - mOptions(), - // TRANSLATORS: quit dialog button - mLogoutQuit(new RadioButton(this, _("Quit"), "quitdialog")), - // TRANSLATORS: quit dialog button - mForceQuit(new RadioButton(this, _("Quit"), "quitdialog")), - mSwitchAccountServer(new RadioButton(this, - // TRANSLATORS: quit dialog button - _("Switch server"), "quitdialog")), - mSwitchCharacter(new RadioButton(this, - // TRANSLATORS: quit dialog button - _("Switch character"), "quitdialog")), - mRate(nullptr), - // TRANSLATORS: quit dialog button - mOkButton(new Button(this, _("OK"), "ok", this)), - // TRANSLATORS: quit dialog button - mCancelButton(new Button(this, _("Cancel"), "cancel", this)), - mMyPointer(pointerToMe), - mNeedForceQuit(false) -{ - addKeyListener(this); - - ContainerPlacer placer = getPlacer(0, 0); - const State state = client->getState(); - mNeedForceQuit = (state == STATE_CHOOSE_SERVER - || state == STATE_CONNECT_SERVER || state == STATE_LOGIN - || state == STATE_PRE_LOGIN || state == STATE_LOGIN_ATTEMPT - || state == STATE_UPDATE || state == STATE_LOAD_DATA); - - // All states, when we're not logged in to someone. - if (mNeedForceQuit) - { - placeOption(placer, mForceQuit); - } - else - { - // Only added if we are connected to an accountserver or gameserver - placeOption(placer, mLogoutQuit); - placeOption(placer, mSwitchAccountServer); - - // Only added if we are connected to a gameserver - if (state == STATE_GAME) - placeOption(placer, mSwitchCharacter); - } - -/* -#ifdef ANDROID - if (config.getBoolValue("rated") == false - && config.getIntValue("gamecount") > 3) - { - mRate = new RadioButton(this, _("Rate in google play"), "quitdialog"); - placeOption(placer, mRate); - mOptions[mOptions.size() - 1]->setSelected(true); - } - else -#endif -*/ - { - mOptions[0]->setSelected(true); - } - - placer = getPlacer(0, 1); - placer(1, 0, mOkButton, 1); - placer(2, 0, mCancelButton, 1); - - reflowLayout(200, 0); - setLocationRelativeTo(getParent()); - setVisible(true); - soundManager.playGuiSound(SOUND_SHOW_WINDOW); - requestModalFocus(); - mOkButton->requestFocus(); -} - -QuitDialog::~QuitDialog() -{ - if (mMyPointer) - *mMyPointer = nullptr; - delete mForceQuit; - mForceQuit = nullptr; - delete mLogoutQuit; - mLogoutQuit = nullptr; - delete mSwitchAccountServer; - mSwitchAccountServer = nullptr; - delete mSwitchCharacter; - mSwitchCharacter = nullptr; -} - -void QuitDialog::placeOption(ContainerPlacer &placer, - RadioButton *const option) -{ - placer(0, static_cast(mOptions.size()), option, 3); - mOptions.push_back(option); -} - -void QuitDialog::action(const gcn::ActionEvent &event) -{ - soundManager.playGuiSound(SOUND_HIDE_WINDOW); - if (event.getId() == "ok") - { - if (viewport) - { - const Map *const map = viewport->getMap(); - if (map) - map->saveExtraLayer(); - } - - if (mForceQuit->isSelected()) - { - client->setState(STATE_FORCE_QUIT); - } - else if (mLogoutQuit->isSelected()) - { - Game::closeDialogs(); - client->setState(STATE_EXIT); - } - else if (mRate && mRate->isSelected()) - { - openBrowser("https://play.google.com/store/apps/details?" - "id=org.evolonline.beta.manaplus"); - config.setValue("rated", true); - if (mNeedForceQuit) - { - client->setState(STATE_FORCE_QUIT); - } - else - { - Game::closeDialogs(); - client->setState(STATE_EXIT); - } - } - else if (Net::getGameHandler()->isConnected() - && mSwitchAccountServer->isSelected()) - { - Game::closeDialogs(); - client->setState(STATE_SWITCH_SERVER); - } - else if (mSwitchCharacter->isSelected()) - { - if (client->getState() == STATE_GAME) - { - Net::getCharServerHandler()->switchCharacter(); - Game::closeDialogs(); - } - } - } - scheduleDelete(); -} - -void QuitDialog::keyPressed(gcn::KeyEvent &keyEvent) -{ - const int actionId = static_cast(&keyEvent)->getActionId(); - int dir = 0; - - switch (actionId) - { - case Input::KEY_GUI_SELECT: - case Input::KEY_GUI_SELECT2: - action(gcn::ActionEvent(nullptr, mOkButton->getActionEventId())); - break; - case Input::KEY_GUI_CANCEL: - action(gcn::ActionEvent(nullptr, - mCancelButton->getActionEventId())); - break; - case Input::KEY_GUI_UP: - dir = -1; - break; - case Input::KEY_GUI_DOWN: - dir = 1; - break; - default: - break; - } - - if (dir != 0) - { - std::vector::const_iterator it = mOptions.begin(); - const std::vector::const_iterator - it_end = mOptions.end(); - - for (; it < it_end; ++it) - { - if ((*it)->isSelected()) - break; - } - - if (it == mOptions.end()) - { - if (mOptions[0]) - mOptions[0]->setSelected(true); - return; - } - else if (it == mOptions.begin() && dir < 0) - { - it = mOptions.end(); - } - - it += dir; - - if (it == mOptions.end()) - it = mOptions.begin(); - - (*it)->setSelected(true); - } -} diff --git a/src/gui/quitdialog.h b/src/gui/quitdialog.h deleted file mode 100644 index b0bde98fc..000000000 --- a/src/gui/quitdialog.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_QUITDIALOG_H -#define GUI_QUITDIALOG_H - -#include "gui/widgets/window.h" - -#include -#include - -#include - -class Button; -class RadioButton; - -/** - * The quit dialog. - * - * \ingroup Interface - */ -class QuitDialog final : public Window, public gcn::ActionListener, - public gcn::KeyListener -{ - public: - /** - * Constructor - * - * @pointerToMe will be set to NULL when the QuitDialog is destroyed - */ - explicit QuitDialog(QuitDialog **const pointerToMe); - - A_DELETE_COPY(QuitDialog) - - /** - * Destructor - */ - ~QuitDialog(); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - void keyPressed(gcn::KeyEvent &keyEvent) override; - - private: - void placeOption(ContainerPlacer &placer, - RadioButton *const option); - std::vector mOptions; - - RadioButton *mLogoutQuit; - RadioButton *mForceQuit; - RadioButton *mSwitchAccountServer; - RadioButton *mSwitchCharacter; - RadioButton *mRate; - Button *mOkButton; - Button *mCancelButton; - - QuitDialog **mMyPointer; - bool mNeedForceQuit; -}; - -#endif // GUI_QUITDIALOG_H diff --git a/src/gui/registerdialog.cpp b/src/gui/registerdialog.cpp deleted file mode 100644 index 183f6b6b8..000000000 --- a/src/gui/registerdialog.cpp +++ /dev/null @@ -1,316 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/registerdialog.h" - -#include "client.h" - -#include "input/keydata.h" -#include "input/keyevent.h" - -#include "gui/okdialog.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/label.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/passwordfield.h" -#include "gui/widgets/radiobutton.h" - -#include "net/logindata.h" -#include "net/loginhandler.h" -#include "net/net.h" - -#include "utils/gettext.h" - -#include "debug.h" - -WrongDataNoticeListener::WrongDataNoticeListener(): - gcn::ActionListener(), - mTarget(nullptr) -{ -} - -void WrongDataNoticeListener::setTarget(TextField *const textField) -{ - mTarget = textField; -} - -void WrongDataNoticeListener::action(const gcn::ActionEvent &event) -{ - if (event.getId() == "ok" && mTarget) - mTarget->requestFocus(); -} - -RegisterDialog::RegisterDialog(LoginData *const data) : - // TRANSLATORS: register dialog name - Window(_("Register"), false, nullptr, "register.xml"), - gcn::ActionListener(), - gcn::KeyListener(), - mLoginData(data), - mUserField(new TextField(this, mLoginData->username)), - mPasswordField(new PasswordField(this, mLoginData->password)), - mConfirmField(new PasswordField(this)), - mEmailField(nullptr), - // TRANSLATORS: register dialog. button. - mRegisterButton(new Button(this, _("Register"), "register", this)), - // TRANSLATORS: register dialog. button. - mCancelButton(new Button(this, _("Cancel"), "cancel", this)), - mMaleButton(nullptr), - mFemaleButton(nullptr), - mOtherButton(nullptr), - mWrongDataNoticeListener(new WrongDataNoticeListener) -{ - setCloseButton(true); - - const int optionalActions = Net::getLoginHandler()-> - supportedOptionalActions(); - - // TRANSLATORS: register dialog. label. - Label *const userLabel = new Label(this, _("Name:")); - // TRANSLATORS: register dialog. label. - Label *const passwordLabel = new Label(this, _("Password:")); - // TRANSLATORS: register dialog. label. - Label *const confirmLabel = new Label(this, _("Confirm:")); - - ContainerPlacer placer; - placer = getPlacer(0, 0); - placer(0, 0, userLabel); - placer(0, 1, passwordLabel); - placer(0, 2, confirmLabel); - - placer(1, 0, mUserField, 3).setPadding(2); - placer(1, 1, mPasswordField, 3).setPadding(2); - placer(1, 2, mConfirmField, 3).setPadding(2); - - int row = 3; - - if (optionalActions & Net::LoginHandler::SetGenderOnRegister) - { - // TRANSLATORS: register dialog. button. - mMaleButton = new RadioButton(this, _("Male"), "sex", true); - // TRANSLATORS: register dialog. button. - mFemaleButton = new RadioButton(this, _("Female"), "sex", false); - if (serverVersion >= 5) - { - // TRANSLATORS: register dialog. button. - mOtherButton = new RadioButton(this, _("Other"), "sex", false); - placer(0, row, mMaleButton); - placer(1, row, mFemaleButton); - placer(2, row, mOtherButton); - } - else - { - placer(1, row, mMaleButton); - placer(2, row, mFemaleButton); - } - - row++; - } - - if (optionalActions & Net::LoginHandler::SetEmailOnRegister) - { - // TRANSLATORS: register dialog. label. - Label *const emailLabel = new Label(this, _("Email:")); - mEmailField = new TextField(this); - placer(0, row, emailLabel); - placer(1, row, mEmailField, 3).setPadding(2); -// row++; - } - - placer = getPlacer(0, 2); - placer(1, 0, mRegisterButton); - placer(2, 0, mCancelButton); - reflowLayout(250, 0); - - mUserField->addKeyListener(this); - mPasswordField->addKeyListener(this); - mConfirmField->addKeyListener(this); - - mUserField->setActionEventId("register"); - mPasswordField->setActionEventId("register"); - mConfirmField->setActionEventId("register"); - - mUserField->addActionListener(this); - mPasswordField->addActionListener(this); - mConfirmField->addActionListener(this); - - center(); - setVisible(true); - mUserField->requestFocus(); - mUserField->setCaretPosition(static_cast( - mUserField->getText().length())); - - mRegisterButton->setEnabled(canSubmit()); -} - -RegisterDialog::~RegisterDialog() -{ - delete mWrongDataNoticeListener; - mWrongDataNoticeListener = nullptr; -} - -void RegisterDialog::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "cancel") - { - close(); - } - else if (eventId == "register" && canSubmit()) - { - const std::string user = mUserField->getText(); - logger->log("RegisterDialog::register Username is %s", user.c_str()); - - std::string errorMsg; - int error = 0; - - const unsigned int minUser = Net::getLoginHandler() - ->getMinUserNameLength(); - const unsigned int maxUser = Net::getLoginHandler() - ->getMaxUserNameLength(); - const unsigned int minPass = Net::getLoginHandler() - ->getMinPasswordLength(); - const unsigned int maxPass = Net::getLoginHandler() - ->getMaxPasswordLength(); - - if (user.length() < minUser) - { - // Name too short - errorMsg = strprintf - // TRANSLATORS: error message - (_("The username needs to be at least %u characters long."), - minUser); - error = 1; - } - else if (user.length() > maxUser - 1) - { - // Name too long - errorMsg = strprintf - // TRANSLATORS: error message - (_("The username needs to be less than %u characters long."), - maxUser); - error = 1; - } - else if (mPasswordField->getText().length() < minPass) - { - // Pass too short - errorMsg = strprintf - // TRANSLATORS: error message - (_("The password needs to be at least %u characters long."), - minPass); - error = 2; - } - else if (mPasswordField->getText().length() > maxPass) - { - // Pass too long - errorMsg = strprintf - // TRANSLATORS: error message - (_("The password needs to be less than %u characters long."), - maxPass); - error = 2; - } - else if (mPasswordField->getText() != mConfirmField->getText()) - { - // Password does not match with the confirmation one - // TRANSLATORS: error message - errorMsg = _("Passwords do not match."); - error = 2; - } - - if (error > 0) - { - if (error == 1) - { - mWrongDataNoticeListener->setTarget(this->mUserField); - } - else if (error == 2) - { - // Reset password confirmation - mPasswordField->setText(""); - mConfirmField->setText(""); - mWrongDataNoticeListener->setTarget(this->mPasswordField); - } - - OkDialog *const dlg = new OkDialog( - // TRANSLATORS: error message - _("Error"), errorMsg, DIALOG_ERROR); - dlg->addActionListener(mWrongDataNoticeListener); - } - else - { - // No errors detected, register the new user. - mRegisterButton->setEnabled(false); - mLoginData->username = mUserField->getText(); - mLoginData->password = mPasswordField->getText(); - if (mFemaleButton && mFemaleButton->isSelected()) - mLoginData->gender = GENDER_FEMALE; - else if (mOtherButton && mOtherButton->isSelected()) - mLoginData->gender = GENDER_OTHER; - else - mLoginData->gender = GENDER_MALE; - - if (mEmailField) - mLoginData->email = mEmailField->getText(); - mLoginData->registerLogin = true; - - client->setState(STATE_REGISTER_ATTEMPT); - } - } -} - -void RegisterDialog::keyPressed(gcn::KeyEvent &keyEvent) -{ - if (keyEvent.isConsumed()) - { - mRegisterButton->setEnabled(canSubmit()); - return; - } - const int actionId = static_cast( - &keyEvent)->getActionId(); - if (actionId == static_cast(Input::KEY_GUI_CANCEL)) - { - action(gcn::ActionEvent(nullptr, mCancelButton->getActionEventId())); - } - else if (actionId == static_cast(Input::KEY_GUI_SELECT) - || actionId == static_cast(Input::KEY_GUI_SELECT2)) - { - action(gcn::ActionEvent(nullptr, mRegisterButton->getActionEventId())); - } - else - { - mRegisterButton->setEnabled(canSubmit()); - } -} - -bool RegisterDialog::canSubmit() const -{ - return !mUserField->getText().empty() && - !mPasswordField->getText().empty() && - !mConfirmField->getText().empty() && - client->getState() == STATE_REGISTER; -} - -void RegisterDialog::close() -{ - client->setState(STATE_LOGIN); - Window::close(); -} diff --git a/src/gui/registerdialog.h b/src/gui/registerdialog.h deleted file mode 100644 index 0bc06b92d..000000000 --- a/src/gui/registerdialog.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_REGISTERDIALOG_H -#define GUI_REGISTERDIALOG_H - -#include "gui/widgets/window.h" - -#include -#include - -class Button; -class LoginData; -class RadioButton; -class TextField; - -/** - * Listener used while dealing with wrong data. It is used to direct the focus - * to the field which contained wrong data when the Ok button was pressed on - * the error notice. - */ -class WrongDataNoticeListener final : public gcn::ActionListener -{ - public: - WrongDataNoticeListener(); - - A_DELETE_COPY(WrongDataNoticeListener) - - void setTarget(TextField *const textField); - - void action(const gcn::ActionEvent &event) override; - private: - TextField *mTarget; -}; - -/** - * The registration dialog. - * - * \ingroup Interface - */ -class RegisterDialog final : public Window, - public gcn::ActionListener, - public gcn::KeyListener -{ - public: - /** - * Constructor. Name, password and server fields will be initialized to - * the information already present in the LoginData instance. - * - * @see Window::Window - */ - explicit RegisterDialog(LoginData *const loginData); - - A_DELETE_COPY(RegisterDialog) - - /** - * Destructor - */ - ~RegisterDialog(); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - /** - * Called when a key is pressed in one of the text fields. - */ - void keyPressed(gcn::KeyEvent &keyEvent) override; - - void close() override; - - private: - /** - * Returns whether submit can be enabled. This is true in the register - * state, when all necessary fields have some text. - */ - bool canSubmit() const; - - LoginData *mLoginData; - TextField *mUserField; - TextField *mPasswordField; - TextField *mConfirmField; - TextField *mEmailField; - Button *mRegisterButton; - Button *mCancelButton; - RadioButton *mMaleButton; - RadioButton *mFemaleButton; - RadioButton *mOtherButton; - WrongDataNoticeListener *mWrongDataNoticeListener; -}; - -#endif // GUI_REGISTERDIALOG_H diff --git a/src/gui/selldialog.cpp b/src/gui/selldialog.cpp deleted file mode 100644 index 4d30a742f..000000000 --- a/src/gui/selldialog.cpp +++ /dev/null @@ -1,389 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/selldialog.h" - -#include "shopitem.h" -#include "units.h" - -#include "being/playerinfo.h" - -#include "gui/confirmdialog.h" -#include "gui/tradewindow.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/label.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/scrollarea.h" -#include "gui/widgets/shopitems.h" -#include "gui/widgets/shoplistbox.h" -#include "gui/widgets/slider.h" - -#include "net/buysellhandler.h" -#include "net/net.h" -#include "net/npchandler.h" - -#include "resources/iteminfo.h" - -#include "utils/gettext.h" - -#include "debug.h" - -SellDialog::DialogList SellDialog::instances; - -SellDialog::SellDialog(const int npcId) : - // TRANSLATORS: sell dialog name - Window(_("Sell"), false, nullptr, "sell.xml"), - gcn::ActionListener(), - gcn::SelectionListener(), - mNpcId(npcId), mMaxItems(0), mAmountItems(0), mNick("") -{ - init(); -} - -SellDialog::SellDialog(std::string nick): - // TRANSLATORS: sell dialog name - Window(_("Sell"), false, nullptr, "sell.xml"), - gcn::ActionListener(), - gcn::SelectionListener(), - mNpcId(-1), mMaxItems(0), mAmountItems(0), mNick(nick) -{ - init(); -} - -void SellDialog::init() -{ - setWindowName("Sell"); - setResizable(true); - setCloseButton(true); - setStickyButtonLock(true); - setMinWidth(260); - setMinHeight(220); - setDefaultSize(260, 230, ImageRect::CENTER); - - // Create a ShopItems instance, that is aware of duplicate entries. - mShopItems = new ShopItems(true); - - mShopItemList = new ShopListBox(this, mShopItems, mShopItems); - mShopItemList->setProtectItems(true); - mScrollArea = new ScrollArea(mShopItemList, - getOptionBool("showbackground"), "sell_background.xml"); - mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - - mSlider = new Slider(1.0); - - mQuantityLabel = new Label(this, strprintf( - "%d / %d", mAmountItems, mMaxItems)); - mQuantityLabel->setAlignment(gcn::Graphics::CENTER); - // TRANSLATORS: sell dialog label - mMoneyLabel = new Label(this, strprintf(_("Price: %s / Total: %s"), - "", "")); - - // TRANSLATORS: sell dialog button - mIncreaseButton = new Button(this, _("+"), "inc", this); - // TRANSLATORS: sell dialog button - mDecreaseButton = new Button(this, _("-"), "dec", this); - // TRANSLATORS: sell dialog button - mSellButton = new Button(this, _("Sell"), "presell", this); - // TRANSLATORS: sell dialog button - mQuitButton = new Button(this, _("Quit"), "quit", this); - // TRANSLATORS: sell dialog button - mAddMaxButton = new Button(this, _("Max"), "max", this); - - mDecreaseButton->adjustSize(); - mDecreaseButton->setWidth(mIncreaseButton->getWidth()); - - mIncreaseButton->setEnabled(false); - mDecreaseButton->setEnabled(false); - mSellButton->setEnabled(false); - mSlider->setEnabled(false); - - mShopItemList->setDistributeMousePressed(false); - mShopItemList->setPriceCheck(false); - mShopItemList->addSelectionListener(this); - mShopItemList->setActionEventId("sell"); - mShopItemList->addActionListener(this); - - mSlider->setActionEventId("slider"); - mSlider->addActionListener(this); - - ContainerPlacer placer; - placer = getPlacer(0, 0); - - placer(0, 0, mScrollArea, 8, 5).setPadding(3); - placer(0, 5, mDecreaseButton); - placer(1, 5, mSlider, 3); - placer(4, 5, mIncreaseButton); - placer(5, 5, mQuantityLabel, 2); - placer(7, 5, mAddMaxButton); - placer(0, 6, mMoneyLabel, 8); - placer(6, 7, mSellButton); - placer(7, 7, mQuitButton); - - Layout &layout = getLayout(); - layout.setRowHeight(0, Layout::AUTO_SET); - - center(); - loadWindowState(); - - instances.push_back(this); - setVisible(true); - enableVisibleSound(true); -} - -SellDialog::~SellDialog() -{ - delete mShopItems; - mShopItems = nullptr; - instances.remove(this); -} - -void SellDialog::reset() -{ - mShopItems->clear(); - mSlider->setValue(0); - mShopItemList->setSelected(-1); - updateButtonsAndLabels(); -} - -void SellDialog::addItem(const Item *const item, const int price) -{ - if (!item) - return; - - mShopItems->addItem2(item->getInvIndex(), item->getId(), - item->getColor(), item->getQuantity(), price); - - mShopItemList->adjustSize(); -} - -void SellDialog::addItem(const int id, const unsigned char color, - const int amount, const int price) -{ - mShopItems->addItem(id, color, amount, price); - mShopItemList->adjustSize(); -} - - -void SellDialog::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - - if (eventId == "quit") - { - close(); - return; - } - - const int selectedItem = mShopItemList->getSelected(); - - // The following actions require a valid item selection - if (selectedItem == -1 - || selectedItem >= mShopItems->getNumberOfElements()) - { - return; - } - - if (eventId == "slider") - { - mAmountItems = static_cast(mSlider->getValue()); - updateButtonsAndLabels(); - } - else if (eventId == "inc" && mAmountItems < mMaxItems) - { - mAmountItems++; - mSlider->setValue(mAmountItems); - updateButtonsAndLabels(); - } - else if (eventId == "dec" && mAmountItems > 1) - { - mAmountItems--; - mSlider->setValue(mAmountItems); - updateButtonsAndLabels(); - } - else if (eventId == "max") - { - mAmountItems = mMaxItems; - mSlider->setValue(mAmountItems); - updateButtonsAndLabels(); - } - else if ((eventId == "presell" || eventId == "sell" || eventId == "yes") - && mAmountItems > 0 && mAmountItems <= mMaxItems) - { - if (mNpcId != -1) - { - ShopItem *const item = mShopItems->at(selectedItem); - if (PlayerInfo::isItemProtected(item->getId())) - return; - if (eventId == "presell") - { - const ItemInfo &info = ItemDB::get(item->getId()); - if (info.isProtected()) - { - ConfirmDialog *const dialog = new ConfirmDialog( - // TRANSLATORS: sell confirmation header - _("sell item"), - // TRANSLATORS: sell confirmation message - strprintf(_("Do you really want to sell %s?"), - info.getName().c_str()), SOUND_REQUEST, false, true); - dialog->addActionListener(this); - return; - } - } - // Attempt sell - mPlayerMoney += - mAmountItems * mShopItems->at(selectedItem)->getPrice(); - mMaxItems -= mAmountItems; - while (mAmountItems > 0) - { -#ifdef MANASERV_SUPPORT - // This order is important, item->getCurrentInvIndex() would - // return the inventory index of the next Duplicate otherwise. - int itemIndex = item->getCurrentInvIndex(); - const int sellCount = item->sellCurrentDuplicate(mAmountItems); - // For Manaserv, the Item id is to be given as index. - if ((Net::getNetworkType() == ServerInfo::MANASERV)) - itemIndex = item->getId(); -#else - // This order is important, item->getCurrentInvIndex() would - // return the inventory index of the next Duplicate otherwise. - const int itemIndex = item->getCurrentInvIndex(); - const int sellCount = item->sellCurrentDuplicate(mAmountItems); -#endif - Net::getNpcHandler()->sellItem(mNpcId, itemIndex, sellCount); - mAmountItems -= sellCount; - } - - mPlayerMoney += - mAmountItems * mShopItems->at(selectedItem)->getPrice(); - mAmountItems = 1; - mSlider->setValue(0); - - if (mMaxItems) - { - updateButtonsAndLabels(); - } - else - { - // All were sold - mShopItemList->setSelected(-1); - delete mShopItems->at(selectedItem); - mShopItems->erase(selectedItem); - - gcn::Rectangle scroll; - scroll.y = mShopItemList->getRowHeight() * (selectedItem + 1); - scroll.height = mShopItemList->getRowHeight(); - mShopItemList->showPart(scroll); - } - } - else - { - ShopItem *const item = mShopItems->at(selectedItem); - Net::getBuySellHandler()->sendSellRequest(mNick, - item, mAmountItems); - - if (tradeWindow) - tradeWindow->addAutoItem(mNick, item, mAmountItems); - } - } -} - -void SellDialog::valueChanged(const gcn::SelectionEvent &event A_UNUSED) -{ - // Reset amount of items and update labels - mAmountItems = 1; - mSlider->setValue(0); - - updateButtonsAndLabels(); - mSlider->setScale(1, mMaxItems); -} - -void SellDialog::setMoney(const int amount) -{ - mPlayerMoney = amount; - mShopItemList->setPlayersMoney(amount); -} - -void SellDialog::updateButtonsAndLabels() -{ - const int selectedItem = mShopItemList->getSelected(); - int income = 0; - ShopItem *item = nullptr; - - if (selectedItem > -1 && mShopItems->at(selectedItem)) - { - item = mShopItems->at(selectedItem); - if (item) - { - mMaxItems = item->getQuantity(); - if (mAmountItems > mMaxItems) - mAmountItems = mMaxItems; - income = mAmountItems * mShopItems->at(selectedItem)->getPrice(); - } - else - { - mMaxItems = 0; - mAmountItems = 0; - } - } - else - { - mMaxItems = 0; - mAmountItems = 0; - } - - // Update Buttons and slider - mSellButton->setEnabled(mAmountItems > 0); - mDecreaseButton->setEnabled(mAmountItems > 1); - mIncreaseButton->setEnabled(mAmountItems < mMaxItems); - mSlider->setEnabled(mMaxItems > 1); - - // Update the quantity and money labels - mQuantityLabel->setCaption(strprintf("%d / %d", mAmountItems, mMaxItems)); - // TRANSLATORS: sell dialog label - mMoneyLabel->setCaption(strprintf(_("Price: %s / Total: %s"), - Units::formatCurrency(income).c_str(), - Units::formatCurrency(mPlayerMoney + income).c_str())); - if (item) - item->update(); -} - -void SellDialog::setVisible(bool visible) -{ - Window::setVisible(visible); - - if (visible) - { - if (mShopItemList) - mShopItemList->requestFocus(); - } - else - { - scheduleDelete(); - } -} - -void SellDialog::closeAll() -{ - FOR_EACH (DialogList::const_iterator, it, instances) - (*it)->close(); -} diff --git a/src/gui/selldialog.h b/src/gui/selldialog.h deleted file mode 100644 index 532244845..000000000 --- a/src/gui/selldialog.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_SELLDIALOG_H -#define GUI_SELLDIALOG_H - -#include "gui/widgets/window.h" - -#include -#include - -class Button; -class Item; -class Label; -class ScrollArea; -class ShopItems; -class ShopListBox; -class Slider; - -/** - * The sell dialog. - * - * \ingroup Interface - */ -class SellDialog final : public Window, - private gcn::ActionListener, - private gcn::SelectionListener -{ - public: - /** - * Constructor. - * - * @see Window::Window - */ - explicit SellDialog(const int npcId); - - /** - * Constructor. - */ - explicit SellDialog(std::string nick); - - A_DELETE_COPY(SellDialog) - - /** - * Destructor - */ - ~SellDialog(); - - void init(); - - /** - * Resets the dialog, clearing inventory. - */ - void reset(); - - /** - * Adds an item to the inventory. - */ - void addItem(const Item *const item, const int price); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - /** - * Updates labels according to selected item. - * - * @see SelectionListener::selectionChanged - */ - void valueChanged(const gcn::SelectionEvent &event) override; - - /** - * Gives Player's Money amount - */ - void setMoney(const int amount); - - /** - * Sets the visibility of this window. - */ - void setVisible(bool visible) override; - - void addItem(const int id, const unsigned char color, - const int amount, const int price); - - /** - * Returns true if any instances exist. - */ - static bool isActive() A_WARN_UNUSED - { return !instances.empty(); } - - /** - * Closes all instances. - */ - static void closeAll(); - - private: - typedef std::list DialogList; - static DialogList instances; - - /** - * Updates the state of buttons and labels. - */ - void updateButtonsAndLabels(); - - int mNpcId; - - Button *mSellButton; - Button *mQuitButton; - Button *mAddMaxButton; - Button *mIncreaseButton; - Button *mDecreaseButton; - ShopListBox *mShopItemList; - ScrollArea *mScrollArea; - Label *mMoneyLabel; - Label *mQuantityLabel; - Slider *mSlider; - - ShopItems *mShopItems; - int mPlayerMoney; - - int mMaxItems; - int mAmountItems; - - std::string mNick; -}; - -#endif // GUI_SELLDIALOG_H diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp deleted file mode 100644 index 2b3f7c697..000000000 --- a/src/gui/serverdialog.cpp +++ /dev/null @@ -1,866 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/serverdialog.h" - -#include "chatlogger.h" -#include "client.h" -#include "configuration.h" -#include "main.h" - -#include "input/keydata.h" -#include "input/keyevent.h" - -#include "gui/editserverdialog.h" -#include "gui/gui.h" -#include "gui/logindialog.h" -#include "gui/sdlfont.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/label.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/listbox.h" -#include "gui/widgets/scrollarea.h" - -#include "utils/gettext.h" -#include "utils/langs.h" - -#include - -#include - -#include "debug.h" - -static const int MAX_SERVERLIST = 15; - -static std::string serverTypeToString(const ServerInfo::Type type) -{ - switch (type) - { - case ServerInfo::TMWATHENA: - return "TmwAthena"; - case ServerInfo::EVOL: - return "Evol"; -#ifdef EATHENA_SUPPORT - case ServerInfo::EATHENA: - return "eAthena"; -#endif -#ifdef MANASERV_SUPPORT - case ServerInfo::MANASERV: - return "ManaServ"; -#else - case ServerInfo::MANASERV: -#endif -#ifndef EATHENA_SUPPORT - case ServerInfo::EATHENA: -#endif - default: - case ServerInfo::UNKNOWN: - return ""; - } -} - -static uint16_t defaultPortForServerType(const ServerInfo::Type type) -{ - switch (type) - { - default: - case ServerInfo::EATHENA: -#ifdef EATHENA_SUPPORT - return 6900; -#else - return 6901; -#endif - case ServerInfo::UNKNOWN: - case ServerInfo::TMWATHENA: - case ServerInfo::EVOL: -#ifdef MANASERV_SUPPORT - return 6901; - case ServerInfo::MANASERV: - return 9601; -#else - case ServerInfo::MANASERV: - return 6901; -#endif - } -} - -ServersListModel::ServersListModel(ServerInfos *const servers, - ServerDialog *const parent) : - mServers(servers), - mVersionStrings(servers->size(), VersionString(0, "")), - mParent(parent) -{ -} - -int ServersListModel::getNumberOfElements() -{ - MutexLocker lock = mParent->lock(); - return static_cast(mServers->size()); -} - -std::string ServersListModel::getElementAt(int elementIndex) -{ - MutexLocker lock = mParent->lock(); - const ServerInfo &server = mServers->at(elementIndex); - std::string myServer; - myServer.append(server.hostname); - return myServer; -} - -void ServersListModel::setVersionString(const int index, - const std::string &version) -{ - if (index < 0 || index >= static_cast(mVersionStrings.size())) - return; - - if (version.empty()) - { - mVersionStrings[index] = VersionString(0, ""); - } - else - { - mVersionStrings[index] = VersionString( - gui->getFont()->getWidth(version), version); - } -} - -class ServersListBox final : public ListBox -{ -public: - ServersListBox(const Widget2 *const widget, - ServersListModel *const model) : - ListBox(widget, model, "serverslistbox.xml"), - mNotSupportedColor(getThemeColor(Theme::SERVER_VERSION_NOT_SUPPORTED)), - mNotSupportedColor2(getThemeColor( - Theme::SERVER_VERSION_NOT_SUPPORTED_OUTLINE)) - { - mHighlightColor = getThemeColor(Theme::HIGHLIGHT); - } - - void draw(gcn::Graphics *graphics) override - { - if (!mListModel) - return; - - ServersListModel *const model = static_cast( - mListModel); - Graphics *const g = static_cast(graphics); - - updateAlpha(); - - mHighlightColor.a = static_cast(mAlpha * 255.0F); - g->setColor(mHighlightColor); - - const int height = getRowHeight(); - mNotSupportedColor.a = static_cast(mAlpha * 255.0F); - - // Draw filled rectangle around the selected list element - if (mSelected >= 0) - { - graphics->fillRectangle(gcn::Rectangle(mPadding, - height * mSelected + mPadding, getWidth() - 2 * mPadding, - height)); - } - - gcn::Font *const font1 = boldFont; - gcn::Font *const font2 = getFont(); - const int fontHeight = font1->getHeight(); - const int pad1 = fontHeight + mPadding; - const int pad2 = height / 4 + mPadding; - const int width = getWidth(); - // Draw the list elements - for (int i = 0, y = 0; i < model->getNumberOfElements(); - ++i, y += height) - { - const ServerInfo &info = model->getServer(i); - - if (mSelected == i) - { - g->setColorAll(mForegroundSelectedColor, - mForegroundSelectedColor2); - } - else - { - g->setColorAll(mForegroundColor, mForegroundColor2); - } - - int top; - int x = mPadding; - - if (!info.name.empty()) - { - x += font1->getWidth(info.name) + 15; - font1->drawString(graphics, info.name, mPadding, y + mPadding); - top = y + pad1; - } - else - { - top = y + pad2; - } - - if (!info.description.empty()) - font2->drawString(graphics, info.description, x, y + mPadding); - font2->drawString(graphics, model->getElementAt(i), mPadding, top); - - if (info.version.first > 0) - { - g->setColorAll(mNotSupportedColor, mNotSupportedColor2); - font2->drawString(graphics, info.version.second, - width - info.version.first - mPadding, top); - } - } - } - - unsigned int getRowHeight() const override - { - return 2 * getFont()->getHeight() + 5; - } -private: - gcn::Color mNotSupportedColor; - gcn::Color mNotSupportedColor2; -}; - - -ServerDialog::ServerDialog(ServerInfo *const serverInfo, - const std::string &dir) : - // TRANSLATORS: servers dialog name - Window(_("Choose Your Server"), false, nullptr, "server.xml"), - gcn::ActionListener(), - gcn::KeyListener(), - gcn::SelectionListener(), - mMutex(), - mDescription(new Label(this, std::string())), - // TRANSLATORS: servers dialog button - mQuitButton(new Button(this, _("Quit"), "quit", this)), - // TRANSLATORS: servers dialog button - mConnectButton(new Button(this, _("Connect"), "connect", this)), - // TRANSLATORS: servers dialog button - mAddEntryButton(new Button(this, _("Add"), "addEntry", this)), - // TRANSLATORS: servers dialog button - mEditEntryButton(new Button(this, _("Edit"), "editEntry", this)), - // TRANSLATORS: servers dialog button - mDeleteButton(new Button(this, _("Delete"), "remove", this)), - // TRANSLATORS: servers dialog button - mLoadButton(new Button(this, _("Load"), "load", this)), - mServers(ServerInfos()), - mServersListModel(new ServersListModel(&mServers, this)), - mServersList(new ServersListBox(this, mServersListModel)), - mDir(dir), - mDownloadStatus(DOWNLOADING_UNKNOWN), - mDownload(nullptr), - mDownloadProgress(-1.0F), - mServerInfo(serverInfo), - mPersistentIPCheckBox(nullptr) -{ - if (isSafeMode) - { - // TRANSLATORS: servers dialog name - setCaption(_("Choose Your Server *** SAFE MODE ***")); - } - - setWindowName("ServerDialog"); - - setCloseButton(true); - - mPersistentIPCheckBox = new CheckBox(this, - // TRANSLATORS: servers dialog checkbox - _("Use same ip for game sub servers"), - config.getBoolValue("usePersistentIP"), - this, "persitent ip"); - - loadCustomServers(); - - mServersList->addMouseListener(this); - - ScrollArea *const usedScroll = new ScrollArea(mServersList, - getOptionBool("showbackground"), "server_background.xml"); - usedScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - - mServersList->addSelectionListener(this); - usedScroll->setVerticalScrollAmount(0); - - place(0, 0, usedScroll, 7, 5).setPadding(3); - place(0, 5, mDescription, 7); - place(0, 6, mPersistentIPCheckBox, 7); - place(0, 7, mAddEntryButton); - place(1, 7, mEditEntryButton); - place(2, 7, mLoadButton); - place(3, 7, mDeleteButton); - place(5, 7, mQuitButton); - place(6, 7, mConnectButton); - - // Make sure the list has enough height - getLayout().setRowHeight(0, 80); - - // Do this manually instead of calling reflowLayout so we can enforce a - // minimum width. - int width = 500; - int height = 350; - - getLayout().reflow(width, height); - setContentSize(width, height); - - setMinWidth(310); - setMinHeight(220); - setDefaultSize(getWidth(), getHeight(), ImageRect::CENTER); - - setResizable(true); - addKeyListener(this); - - loadWindowState(); - - setVisible(true); - - mConnectButton->requestFocus(); - - loadServers(true); - - mServersList->setSelected(0); // Do this after for the Delete button - - if (needUpdateServers()) - downloadServerList(); -} - -ServerDialog::~ServerDialog() -{ - if (mDownload) - { - mDownload->cancel(); - delete mDownload; - mDownload = nullptr; - } - delete mServersListModel; - mServersListModel = nullptr; -} - -void ServerDialog::connectToSelectedServer() -{ - if (client->getState() == STATE_CONNECT_SERVER) - return; - - const int index = mServersList->getSelected(); - if (index < 0) - return; - - if (mDownload) - mDownload->cancel(); - - mQuitButton->setEnabled(false); - mConnectButton->setEnabled(false); - mLoadButton->setEnabled(false); - - ServerInfo server = mServers.at(index); - mServerInfo->hostname = server.hostname; - mServerInfo->althostname = server.althostname; - mServerInfo->port = server.port; - mServerInfo->type = server.type; - mServerInfo->name = server.name; - mServerInfo->description = server.description; - mServerInfo->registerUrl = server.registerUrl; - mServerInfo->onlineListUrl = server.onlineListUrl; - mServerInfo->supportUrl = server.supportUrl; - mServerInfo->save = true; - - if (chatLogger) - chatLogger->setServerName(mServerInfo->hostname); - - saveCustomServers(*mServerInfo); - - if (!LoginDialog::savedPasswordKey.empty()) - { - if (mServerInfo->hostname != LoginDialog::savedPasswordKey) - LoginDialog::savedPassword.clear(); - } - - config.setValue("usePersistentIP", - mPersistentIPCheckBox->isSelected()); - client->setState(STATE_CONNECT_SERVER); -} - -void ServerDialog::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "connect") - { - connectToSelectedServer(); - } - else if (eventId == "quit") - { - close(); - } - else if (eventId == "load") - { - downloadServerList(); - } - else if (eventId == "addEntry") - { - new EditServerDialog(this, ServerInfo(), -1); - } - else if (eventId == "editEntry") - { - const int index = mServersList->getSelected(); - if (index >= 0) - new EditServerDialog(this, mServers.at(index), index); - } - else if (eventId == "remove") - { - const int index = mServersList->getSelected(); - if (index >= 0) - { - mServersList->setSelected(0); - mServers.erase(mServers.begin() + index); - saveCustomServers(); - } - } -} - -void ServerDialog::keyPressed(gcn::KeyEvent &keyEvent) -{ - switch (static_cast(&keyEvent)->getActionId()) - { - case Input::KEY_GUI_CANCEL: - keyEvent.consume(); - client->setState(STATE_EXIT); - return; - - case Input::KEY_GUI_SELECT: - case Input::KEY_GUI_SELECT2: - keyEvent.consume(); - action(gcn::ActionEvent(nullptr, - mConnectButton->getActionEventId())); - return; - - case Input::KEY_GUI_INSERT: - new EditServerDialog(this, ServerInfo(), -1); - return; - - case Input::KEY_GUI_DELETE: - { - const int index = mServersList->getSelected(); - if (index >= 0) - { - mServersList->setSelected(0); - mServers.erase(mServers.begin() + index); - saveCustomServers(); - } - return; - } - - case Input::KEY_GUI_BACKSPACE: - { - const int index = mServersList->getSelected(); - if (index >= 0) - new EditServerDialog(this, mServers.at(index), index); - return; - } - - default: - break; - } - if (!keyEvent.isConsumed()) - mServersList->keyPressed(keyEvent); -} - -void ServerDialog::valueChanged(const gcn::SelectionEvent &) -{ - const int index = mServersList->getSelected(); - if (index == -1) - { - mDeleteButton->setEnabled(false); - return; - } - mDeleteButton->setEnabled(true); -} - -void ServerDialog::mouseClicked(gcn::MouseEvent &mouseEvent) -{ - if (mouseEvent.getClickCount() == 2 && - mouseEvent.getSource() == mServersList) - { - action(gcn::ActionEvent(mConnectButton, - mConnectButton->getActionEventId())); - } -} - -void ServerDialog::logic() -{ - BLOCK_START("ServerDialog::logic") - { - MutexLocker tempLock(&mMutex); - if (mDownloadStatus == DOWNLOADING_COMPLETE) - { - mDownloadStatus = DOWNLOADING_OVER; - mDescription->setCaption(std::string()); - } - else if (mDownloadStatus == DOWNLOADING_IN_PROGRESS) - { - // TRANSLATORS: servers dialog label - mDescription->setCaption(strprintf(_("Downloading server list..." - "%2.2f%%"), static_cast(mDownloadProgress * 100))); - } - else if (mDownloadStatus == DOWNLOADING_IDLE) - { - // TRANSLATORS: servers dialog label - mDescription->setCaption(_("Waiting for server...")); - } - else if (mDownloadStatus == DOWNLOADING_PREPARING) - { - // TRANSLATORS: servers dialog label - mDescription->setCaption(_("Preparing download")); - } - else if (mDownloadStatus == DOWNLOADING_ERROR) - { - // TRANSLATORS: servers dialog label - mDescription->setCaption(_("Error retreiving server list!")); - } - } - - Window::logic(); - BLOCK_END("ServerDialog::logic") -} - -void ServerDialog::downloadServerList() -{ - // Try to load the configuration value for the onlineServerList - std::string listFile = branding.getStringValue("onlineServerList"); - - if (listFile.empty()) - listFile = config.getStringValue("onlineServerList"); - - // Fall back to manaplus.org when neither branding - // nor config set it - if (listFile.empty()) - listFile = "http://manaplus.org/serverlist.xml"; - - if (mDownload) - { - mDownload->cancel(); - delete mDownload; - mDownload = nullptr; - } - - mDownload = new Net::Download(this, listFile, &downloadUpdate); - mDownload->setFile(std::string(mDir).append("/").append( - branding.getStringValue("onlineServerFile"))); - mDownload->start(); - - config.setValue("serverslistupdate", getDateString()); -} - -void ServerDialog::loadServers(const bool addNew) -{ - XML::Document doc(std::string(mDir).append("/").append( - branding.getStringValue("onlineServerFile")), false); - const XmlNodePtr rootNode = doc.rootNode(); - - if (!rootNode || !xmlNameEqual(rootNode, "serverlist")) - { - logger->log1("Error loading server list!"); - return; - } - - const int ver = XML::getProperty(rootNode, "version", 0); - if (ver != 1) - { - logger->log("Error: unsupported online server list version: %d", - ver); - return; - } - - const std::string lang = getLangShort(); - const std::string description2("description_" + lang); - - for_each_xml_child_node(serverNode, rootNode) - { - if (!xmlNameEqual(serverNode, "server")) - continue; - - const std::string type = XML::getProperty( - serverNode, "type", "unknown"); - ServerInfo server; - server.type = ServerInfo::parseType(type); - - // Ignore unknown server types - if (server.type == ServerInfo::UNKNOWN) - { - logger->log("Ignoring server entry with unknown type: %s", - type.c_str()); - continue; - } - - server.name = XML::getProperty(serverNode, "name", std::string()); - std::string version = XML::getProperty(serverNode, "minimumVersion", - std::string()); - - const bool meetsMinimumVersion = (compareStrI(version, SMALL_VERSION) - <= 0); - - // For display in the list - if (meetsMinimumVersion) - version.clear(); - else if (version.empty()) - { - // TRANSLATORS: servers dialog label - version = _("requires a newer version"); - } - else - { - // TRANSLATORS: servers dialog label - version = strprintf(_("requires v%s"), version.c_str()); - } - - const gcn::Font *const font = gui->getFont(); - - for_each_xml_child_node(subNode, serverNode) - { - if (xmlNameEqual(subNode, "connection")) - { - server.hostname = XML::getProperty(subNode, "hostname", ""); - server.althostname = XML::getProperty( - subNode, "althostname", ""); - server.port = static_cast( - XML::getProperty(subNode, "port", 0)); - - if (server.port == 0) - { - // If no port is given, use the default for the given type - server.port = defaultPortForServerType(server.type); - } - } - else if ((xmlNameEqual(subNode, "description") - && server.description.empty()) || (!lang.empty() - && xmlNameEqual(subNode, description2.c_str()))) - { - server.description = reinterpret_cast( - subNode->xmlChildrenNode->content); - } - else if (xmlNameEqual(subNode, "registerurl")) - { - server.registerUrl = reinterpret_cast( - subNode->xmlChildrenNode->content); - } - else if (xmlNameEqual(subNode, "onlineListUrl")) - { - server.onlineListUrl = reinterpret_cast( - subNode->xmlChildrenNode->content); - } - else if (xmlNameEqual(subNode, "support")) - { - server.supportUrl = reinterpret_cast( - subNode->xmlChildrenNode->content); - } - } - - server.version.first = font->getWidth(version); - server.version.second = version; - - MutexLocker tempLock(&mMutex); - // Add the server to the local list if it's not already present - bool found = false; - for (unsigned int i = 0, sz = static_cast( - mServers.size()); i < sz; i++) - { - if (mServers[i] == server) - { - // Use the name listed in the server list - mServers[i].name = server.name; - mServers[i].version = server.version; - mServers[i].description = server.description; - mServers[i].registerUrl = server.registerUrl; - mServers[i].onlineListUrl = server.onlineListUrl; - mServers[i].supportUrl = server.supportUrl; - mServers[i].althostname = server.althostname; - mServersListModel->setVersionString(i, version); - found = true; - break; - } - } - if (!found && addNew) - mServers.push_back(server); - } - if (mServersList->getSelected() < 0) - mServersList->setSelected(0); -} - -void ServerDialog::loadCustomServers() -{ - for (int i = 0; i < MAX_SERVERLIST; ++i) - { - const std::string index = toString(i); - const std::string nameKey("MostUsedServerDescName" + index); - const std::string descKey("MostUsedServerDescription" + index); - const std::string hostKey("MostUsedServerName" + index); - const std::string typeKey("MostUsedServerType" + index); - const std::string portKey("MostUsedServerPort" + index); - const std::string onlineListUrlKey - ("MostUsedServerOnlineList" + index); - - ServerInfo server; - server.name = config.getValue(nameKey, ""); - server.description = config.getValue(descKey, ""); - server.onlineListUrl = config.getValue(onlineListUrlKey, ""); - server.hostname = config.getValue(hostKey, ""); - server.type = ServerInfo::parseType(config.getValue(typeKey, "")); - - const int defaultPort = defaultPortForServerType(server.type); - server.port = static_cast( - config.getValue(portKey, defaultPort)); - - // skip invalid server - if (!server.isValid()) - continue; - - server.save = true; - mServers.push_back(server); - } -} - -void ServerDialog::saveCustomServers(const ServerInfo ¤tServer, - const int index) -{ - // Make sure the current server is mentioned first - if (currentServer.isValid()) - { - if (index >= 0 && static_cast(index) < mServers.size()) - { - mServers[index] = currentServer; - } - else - { - FOR_EACH (ServerInfos::iterator, i, mServers) - { - if (*i == currentServer) - { - mServers.erase(i); - break; - } - } - mServers.insert(mServers.begin(), currentServer); - } - } - - int savedServerCount = 0; - - for (unsigned i = 0, sz = static_cast(mServers.size()); - i < sz && savedServerCount < MAX_SERVERLIST; ++ i) - { - const ServerInfo &server = mServers.at(i); - - // Only save servers that were loaded from settings - if (!(server.save && server.isValid())) - continue; - - const std::string num = toString(savedServerCount); - const std::string nameKey("MostUsedServerDescName" + num); - const std::string descKey("MostUsedServerDescription" + num); - const std::string hostKey("MostUsedServerName" + num); - const std::string typeKey("MostUsedServerType" + num); - const std::string portKey("MostUsedServerPort" + num); - const std::string onlineListUrlKey - ("MostUsedServerOnlineList" + num); - - config.setValue(nameKey, toString(server.name)); - config.setValue(descKey, toString(server.description)); - config.setValue(onlineListUrlKey, toString(server.onlineListUrl)); - config.setValue(hostKey, toString(server.hostname)); - config.setValue(typeKey, serverTypeToString(server.type)); - config.setValue(portKey, toString(server.port)); - ++ savedServerCount; - } - - // Insert an invalid entry at the end to make the loading stop there - if (savedServerCount < MAX_SERVERLIST) - config.setValue("MostUsedServerName" + toString(savedServerCount), ""); -} - -int ServerDialog::downloadUpdate(void *ptr, DownloadStatus status, - size_t total, size_t remaining) -{ - if (!ptr || status == DOWNLOAD_STATUS_CANCELLED) - return -1; - - ServerDialog *const sd = reinterpret_cast(ptr); - bool finished = false; - - if (!sd->mDownload) - return -1; - - if (status == DOWNLOAD_STATUS_COMPLETE) - { - finished = true; - } - else if (status < 0) - { - logger->log("Error retreiving server list: %s\n", - sd->mDownload->getError()); - sd->mDownloadStatus = DOWNLOADING_ERROR; - } - else - { - float progress = static_cast(remaining); - if (total) - progress /= static_cast(total); - - if (progress != progress || progress < 0.0F) - progress = 0.0f; - else if (progress > 1.0F) - progress = 1.0F; - - MutexLocker lock1(&sd->mMutex); - sd->mDownloadStatus = DOWNLOADING_IN_PROGRESS; - sd->mDownloadProgress = progress; - } - - if (finished) - { - sd->loadServers(); - MutexLocker lock1(&sd->mMutex); - sd->mDownloadStatus = DOWNLOADING_COMPLETE; - } - - return 0; -} - -void ServerDialog::updateServer(const ServerInfo &server, const int index) -{ - saveCustomServers(server, index); -} - -bool ServerDialog::needUpdateServers() const -{ - if (mServers.empty() || config.getStringValue("serverslistupdate") - != getDateString()) - { - return true; - } - - return false; -} - -void ServerDialog::close() -{ - if (mDownload) - mDownload->cancel(); - client->setState(STATE_FORCE_QUIT); - Window::close(); -} diff --git a/src/gui/serverdialog.h b/src/gui/serverdialog.h deleted file mode 100644 index ea6954e15..000000000 --- a/src/gui/serverdialog.h +++ /dev/null @@ -1,194 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_SERVERDIALOG_H -#define GUI_SERVERDIALOG_H - -#include "gui/widgets/window.h" -#include "gui/widgets/checkbox.h" - -#include "net/download.h" -#include "net/serverinfo.h" - -#include "utils/mutex.h" - -#include -#include -#include -#include - -#include -#include - -class Button; -class Label; -class ListBox; -class ServerDialog; - -/** - * Server and Port List Model - */ -class ServersListModel final : public gcn::ListModel -{ - public: - typedef std::pair VersionString; - - ServersListModel(ServerInfos *const servers, - ServerDialog *const parent); - - A_DELETE_COPY(ServersListModel) - - /** - * Used to get number of line in the list - */ - int getNumberOfElements() override A_WARN_UNUSED; - - /** - * Used to get an element from the list - */ - std::string getElementAt(int elementIndex) override A_WARN_UNUSED; - - /** - * Used to get the corresponding Server struct - */ - const ServerInfo &getServer(const int elementIndex) const A_WARN_UNUSED - { return mServers->at(elementIndex); } - - void setVersionString(const int index, const std::string &version); - - private: - typedef std::vector VersionStrings; - - ServerInfos *mServers; - VersionStrings mVersionStrings; - ServerDialog *mParent; -}; - - -/** - * The server choice dialog. - * - * \ingroup Interface - */ -class ServerDialog final : public Window, - public gcn::ActionListener, - public gcn::KeyListener, - public gcn::SelectionListener -{ - public: - /** - * Constructor - * - * @see Window::Window - */ - ServerDialog(ServerInfo *const serverInfo, const std::string &dir); - - A_DELETE_COPY(ServerDialog) - - /** - * Destructor - */ - ~ServerDialog(); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - void keyPressed(gcn::KeyEvent &keyEvent) override; - - /** - * Called when the selected value changed in the servers list box. - */ - void valueChanged(const gcn::SelectionEvent &event) override; - - void mouseClicked(gcn::MouseEvent &mouseEvent) override; - - void logic() override; - - void updateServer(const ServerInfo &server, const int index); - - void connectToSelectedServer(); - - void close() override; - - protected: - friend class ServersListModel; - - MutexLocker lock() - { return MutexLocker(&mMutex); } - - private: - friend class EditServerDialog; - - /** - * Called to load a list of available server from an online xml file. - */ - void downloadServerList(); - - void loadServers(const bool addNew = true); - - void loadCustomServers(); - - void saveCustomServers(const ServerInfo ¤tServer = ServerInfo(), - const int index = -1); - - bool needUpdateServers() const; - - static int downloadUpdate(void *ptr, DownloadStatus status, - size_t total, size_t remaining); - - Mutex mMutex; - Label *mDescription; - Button *mQuitButton; - Button *mConnectButton; - Button *mAddEntryButton; - Button *mEditEntryButton; - Button *mDeleteButton; - Button *mLoadButton; - - ServerInfos mServers; - ServersListModel *mServersListModel; - ListBox *mServersList; - - const std::string &mDir; - - enum ServerDialogDownloadStatus - { - DOWNLOADING_UNKNOWN = 0, - DOWNLOADING_ERROR, - DOWNLOADING_PREPARING, - DOWNLOADING_IDLE, - DOWNLOADING_IN_PROGRESS, - DOWNLOADING_COMPLETE, - DOWNLOADING_OVER - }; - - /** Status of the current download. */ - ServerDialogDownloadStatus mDownloadStatus; - Net::Download *mDownload; - float mDownloadProgress; - ServerInfo *mServerInfo; - CheckBox *mPersistentIPCheckBox; -}; - -#endif // GUI_SERVERDIALOG_H diff --git a/src/gui/setup.cpp b/src/gui/setup.cpp deleted file mode 100644 index 77d2c2e5c..000000000 --- a/src/gui/setup.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/setup.h" - -#include "chatwindow.h" -#include "configuration.h" -#include "game.h" -#include "main.h" -#include "touchmanager.h" - -#include "gui/setup_audio.h" -#include "gui/setup_chat.h" -#include "gui/setup_colors.h" -#include "gui/setup_joystick.h" -#include "gui/setup_other.h" -#include "gui/setup_theme.h" -#include "gui/setup_input.h" -#include "gui/setup_perfomance.h" -#include "gui/setup_players.h" -#include "gui/setup_relations.h" -#include "gui/setup_touch.h" -#include "gui/setup_video.h" -#include "gui/setup_visual.h" - -#include "gui/widgets/label.h" - -#include "utils/dtor.h" -#include "utils/gettext.h" - -#include "debug.h" - -extern Window *statusWindow; -Setup *setupWindow; - -Setup::Setup() : - // TRANSLATORS: setup window name - Window(_("Setup"), false, nullptr, "setup.xml"), - gcn::ActionListener(), - mTabs(), - mWindowsToReset(), - mButtons(), - mResetWindows(nullptr), - mPanel(new TabbedArea(this)), - mVersion(new Label(this, FULL_VERSION)) -{ - setCloseButton(true); - setResizable(true); - setStickyButtonLock(true); - - int width = 620; - const int height = 450; - - if (config.getIntValue("screenwidth") >= 730) - width += 100; - - setContentSize(width, height); - setMinWidth(310); - setMinHeight(210); - - static const char *buttonNames[] = - { - // TRANSLATORS: setup button - N_("Apply"), - // TRANSLATORS: setup button - N_("Cancel"), - // TRANSLATORS: setup button - N_("Store"), - // TRANSLATORS: setup button - N_("Reset Windows"), - nullptr - }; - int x = width; - const int buttonPadding = getOption("buttonPadding", 5); - for (const char ** curBtn = buttonNames; *curBtn; ++ curBtn) - { - Button *const btn = new Button(this, gettext(*curBtn), *curBtn, this); - mButtons.push_back(btn); - x -= btn->getWidth() + buttonPadding; - btn->setPosition(x, height - btn->getHeight() - buttonPadding); - add(btn); - - // Store this button, as it needs to be enabled/disabled - if (!strcmp(*curBtn, "Reset Windows")) - mResetWindows = btn; - } - - mPanel->setDimension(gcn::Rectangle(5, 5, width - 10, height - 40)); - mPanel->enableScrollButtons(true); - - mTabs.push_back(new Setup_Video(this)); - mTabs.push_back(new Setup_Visual(this)); - mTabs.push_back(new Setup_Audio(this)); - mTabs.push_back(new Setup_Perfomance(this)); - mTabs.push_back(new Setup_Touch(this)); - mTabs.push_back(new Setup_Input(this)); - mTabs.push_back(new Setup_Joystick(this)); - mTabs.push_back(new Setup_Colors(this)); - mTabs.push_back(new Setup_Chat(this)); - mTabs.push_back(new Setup_Players(this)); - mTabs.push_back(new Setup_Relations(this)); - mTabs.push_back(new Setup_Theme(this)); - mTabs.push_back(new Setup_Other(this)); - - FOR_EACH (std::list::const_iterator, i, mTabs) - { - SetupTab *const tab = *i; - mPanel->addTab(tab->getName(), tab); - } - add(mPanel); - - if (mResetWindows) - { - mVersion->setPosition(9, - height - mVersion->getHeight() - mResetWindows->getHeight() - 9); - } - else - { - mVersion->setPosition(9, height - mVersion->getHeight() - 30); - } - add(mVersion); - - center(); - - widgetResized(gcn::Event(nullptr)); - setInGame(false); - enableVisibleSound(true); -} - -Setup::~Setup() -{ - delete_all(mTabs); - mButtons.clear(); -} - -void Setup::action(const gcn::ActionEvent &event) -{ - if (Game::instance()) - Game::instance()->resetAdjustLevel(); - const std::string &eventId = event.getId(); - - if (eventId == "Apply") - { - setVisible(false); - for_each(mTabs.begin(), mTabs.end(), std::mem_fun(&SetupTab::apply)); - } - else if (eventId == "Cancel") - { - doCancel(); - } - else if (eventId == "Store") - { - if (chatWindow) - chatWindow->saveState(); - config.write(); - serverConfig.write(); - } - else if (eventId == "Reset Windows") - { - // Bail out if this action happens to be activated before the windows - // are created (though it should be disabled then) - if (!statusWindow) - return; - - FOR_EACH (std::list::const_iterator, it, mWindowsToReset) - { - if (*it) - (*it)->resetToDefaultSize(); - } - } -} - -void Setup::setInGame(const bool inGame) -{ - mResetWindows->setEnabled(inGame); -} - -void Setup::externalUpdate() -{ - FOR_EACH (std::list::const_iterator, it, mTabs) - { - if (*it) - (*it)->externalUpdated(); - } -} - -void Setup::registerWindowForReset(Window *const window) -{ - mWindowsToReset.push_back(window); -} - -void Setup::doCancel() -{ - setVisible(false); - for_each(mTabs.begin(), mTabs.end(), std::mem_fun(&SetupTab::cancel)); -} - -void Setup::activateTab(const std::string &name) -{ - std::string tmp = gettext(name.c_str()); - mPanel->setSelectedTabByName(tmp); -} - -void Setup::setVisible(bool visible) -{ - touchManager.setTempHide(visible); - Window::setVisible(visible); -} - -void Setup::widgetResized(const gcn::Event &event) -{ - Window::widgetResized(event); - - const gcn::Rectangle area = getChildrenArea(); - int x = area.width; - const int height = area.height; - const int width = area.width; - const int buttonPadding = getOption("buttonPadding", 5); - mPanel->setDimension(gcn::Rectangle(5, 5, width - 10, height - 40)); - FOR_EACH (std::vector::iterator, it, mButtons) - { - Button *const btn = *it; - x -= btn->getWidth() + buttonPadding; - btn->setPosition(x, height - btn->getHeight() - buttonPadding); - } - if (mResetWindows) - { - mVersion->setPosition(9, - height - mVersion->getHeight() - mResetWindows->getHeight() - 9); - } - else - { - mVersion->setPosition(9, height - mVersion->getHeight() - 30); - } -} diff --git a/src/gui/setup.h b/src/gui/setup.h deleted file mode 100644 index aeb7cc635..000000000 --- a/src/gui/setup.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_SETUP_H -#define GUI_SETUP_H - -#include "gui/widgets/tabbedarea.h" - -#include "gui/widgets/window.h" - -#include - -#include - -class Label; -class SetupTab; - -/** - * The setup dialog. Displays several tabs for configuring different aspects - * of the game. - * - * \ingroup GUI - */ -class Setup final : public Window, public gcn::ActionListener -{ - public: - Setup(); - - A_DELETE_COPY(Setup) - - ~Setup(); - - void action(const gcn::ActionEvent &event) override; - - void setInGame(const bool inGame); - - void externalUpdate(); - - void registerWindowForReset(Window *const window); - - void clearWindowsForReset() - { mWindowsToReset.clear(); } - - void doCancel(); - - void activateTab(const std::string &name); - - void setVisible(bool visible) override; - - void widgetResized(const gcn::Event &event) override; - - private: - std::list mTabs; - std::list mWindowsToReset; - std::vector mButtons; - Button *mResetWindows; - TabbedArea *mPanel; - Label *mVersion; -}; - -extern Setup* setupWindow; - -#endif // GUI_SETUP_H diff --git a/src/gui/setup_chat.cpp b/src/gui/setup_chat.cpp index cf2958e4d..4874e4291 100644 --- a/src/gui/setup_chat.cpp +++ b/src/gui/setup_chat.cpp @@ -22,7 +22,7 @@ #include "gui/setup_chat.h" -#include "gui/chatwindow.h" +#include "gui/windows/chatwindow.h" #include "gui/widgets/layouthelper.h" #include "gui/widgets/scrollarea.h" diff --git a/src/gui/setup_input.cpp b/src/gui/setup_input.cpp index 3873c2dd3..423dce947 100644 --- a/src/gui/setup_input.cpp +++ b/src/gui/setup_input.cpp @@ -28,9 +28,10 @@ #include "input/inputmanager.h" #include "input/keyboardconfig.h" -#include "gui/okdialog.h" #include "gui/setupactiondata.h" +#include "gui/windows/okdialog.h" + #include "gui/widgets/button.h" #include "gui/widgets/layouthelper.h" #include "gui/widgets/listbox.h" diff --git a/src/gui/setup_theme.cpp b/src/gui/setup_theme.cpp index ca38a76d8..029bc07f1 100644 --- a/src/gui/setup_theme.cpp +++ b/src/gui/setup_theme.cpp @@ -23,7 +23,8 @@ #include "gui/setup_theme.h" #include "gui/gui.h" -#include "gui/okdialog.h" + +#include "gui/windows/okdialog.h" #include "gui/widgets/button.h" #include "gui/widgets/dropdown.h" diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp index 881aa69d4..34e17a1c6 100644 --- a/src/gui/setup_video.cpp +++ b/src/gui/setup_video.cpp @@ -27,8 +27,8 @@ #include "graphicsmanager.h" -#include "gui/okdialog.h" -#include "gui/textdialog.h" +#include "gui/windows/okdialog.h" +#include "gui/windows/textdialog.h" #include "gui/widgets/button.h" #include "gui/widgets/checkbox.h" diff --git a/src/gui/shopwindow.cpp b/src/gui/shopwindow.cpp deleted file mode 100644 index feafdb51d..000000000 --- a/src/gui/shopwindow.cpp +++ /dev/null @@ -1,867 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/shopwindow.h" - -#include "gui/buydialog.h" -#include "gui/itemamountwindow.h" -#include "gui/selldialog.h" -#include "gui/tradewindow.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/chattab.h" -#include "gui/widgets/checkbox.h" -#include "gui/widgets/label.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/scrollarea.h" -#include "gui/widgets/shopitems.h" -#include "gui/widgets/shoplistbox.h" - -#include "actorspritemanager.h" -#include "auctionmanager.h" -#include "client.h" -#include "configuration.h" -#include "confirmdialog.h" -#include "inventory.h" -#include "item.h" -#include "shopitem.h" -#include "soundconsts.h" -#include "soundmanager.h" - -#include "being/localplayer.h" -#include "being/playerinfo.h" -#include "being/playerrelations.h" - -#include "net/net.h" -#include "net/chathandler.h" -#include "net/tradehandler.h" - -#include "resources/iteminfo.h" - -#include "utils/gettext.h" - -#include - -#include - -#include "debug.h" - -extern std::string tradePartnerName; -ShopWindow::DialogList ShopWindow::instances; - -ShopWindow::ShopWindow(): - // TRANSLATORS: shop window name - Window(_("Personal Shop"), false, nullptr, "shop.xml"), - gcn::ActionListener(), - gcn::SelectionListener(), - // TRANSLATORS: shop window button - mCloseButton(new Button(this, _("Close"), "close", this)), - mBuyShopItems(new ShopItems), - mSellShopItems(new ShopItems), - mBuyShopItemList(new ShopListBox(this, mBuyShopItems, mBuyShopItems)), - mSellShopItemList(new ShopListBox(this, mSellShopItems, mSellShopItems)), - mBuyScrollArea(new ScrollArea(mBuyShopItemList, - getOptionBool("showbuybackground"), "shop_buy_background.xml")), - mSellScrollArea(new ScrollArea(mSellShopItemList, - getOptionBool("showsellbackground"), "shop_sell_background.xml")), - // TRANSLATORS: shop window label - mBuyLabel(new Label(this, _("Buy items"))), - // TRANSLATORS: shop window label - mSellLabel(new Label(this, _("Sell items"))), - // TRANSLATORS: shop window label - mBuyAddButton(new Button(this, _("Add"), "add buy", this)), - // TRANSLATORS: shop window label - mBuyDeleteButton(new Button(this, _("Delete"), "delete buy", this)), - // TRANSLATORS: shop window label - mBuyAnnounceButton(new Button(this, _("Announce"), "announce buy", this)), - mBuyAuctionButton(nullptr), - // TRANSLATORS: shop window button - mSellAddButton(new Button(this, _("Add"), "add sell", this)), - // TRANSLATORS: shop window button - mSellDeleteButton(new Button(this, _("Delete"), "delete sell", this)), - // TRANSLATORS: shop window button - mSellAnnounceButton(new Button(this, _("Announce"), - "announce sell", this)), - mSellAuctionButton(nullptr), - // TRANSLATORS: shop window checkbox - mAnnounceLinks(new CheckBox(this, _("Show links in announce"), false, - this, "link announce")), - mSelectedItem(-1), - mAnnonceTime(0), - mLastRequestTimeList(0), - mLastRequestTimeItem(0), - mRandCounter(0), - mAcceptPlayer(""), - mTradeItem(nullptr), - mTradeNick(""), - mTradeMoney(0) -{ - setWindowName("Personal Shop"); - setResizable(true); - setCloseButton(true); - setStickyButtonLock(true); - setMinWidth(260); - setMinHeight(220); - if (mainGraphics->mWidth > 600) - setDefaultSize(500, 300, ImageRect::CENTER); - else - setDefaultSize(380, 300, ImageRect::CENTER); - - mAnnounceCounter[BUY] = 0; - mAnnounceCounter[SELL] = 0; - - loadList(); - - mBuyShopItemList->setPriceCheck(false); - mSellShopItemList->setPriceCheck(false); - - mBuyScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - mSellScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - - mBuyShopItemList->addSelectionListener(this); - mSellShopItemList->addSelectionListener(this); - - ContainerPlacer placer; - placer = getPlacer(0, 0); - - placer(0, 0, mBuyLabel, 8).setPadding(3); - placer(8, 0, mSellLabel, 8).setPadding(3); - placer(0, 1, mBuyScrollArea, 8, 5).setPadding(3); - placer(8, 1, mSellScrollArea, 8, 5).setPadding(3); - placer(0, 6, mBuyAddButton); - placer(1, 6, mBuyDeleteButton); - placer(3, 6, mBuyAnnounceButton); - placer(8, 6, mSellAddButton); - placer(9, 6, mSellDeleteButton); - placer(11, 6, mSellAnnounceButton); - placer(0, 7, mAnnounceLinks, 8); - placer(15, 7, mCloseButton); - - if (auctionManager && auctionManager->getEnableAuctionBot()) - { - mBuyAuctionButton = new Button(this, - // TRANSLATORS: shop window button - _("Auction"), "auction buy", this); - mSellAuctionButton = new Button(this, - // TRANSLATORS: shop window button - _("Auction"), "auction sell", this); - placer(4, 6, mBuyAuctionButton); - placer(12, 6, mSellAuctionButton); - } - else - { - mBuyAuctionButton = nullptr; - mSellAuctionButton = nullptr; - } - - Layout &layout = getLayout(); - layout.setRowHeight(0, Layout::AUTO_SET); - - center(); - loadWindowState(); - - instances.push_back(this); - setVisible(false); - enableVisibleSound(true); - - updateButtonsAndLabels(); -} - -ShopWindow::~ShopWindow() -{ - saveList(); - - delete mBuyShopItems; - mBuyShopItems = nullptr; - - delete mSellShopItems; - mSellShopItems = nullptr; - - instances.remove(this); -} - -void ShopWindow::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "close") - { - close(); - return; - } - else if (eventId == "yes") - { - startTrade(); - } - else if (eventId == "no") - { - mTradeNick.clear(); - } - else if (eventId == "ignore") - { - player_relations.ignoreTrade(mTradeNick); - mTradeNick.clear(); - } - else if (eventId == "delete buy" && mBuyShopItemList - && mBuyShopItemList->getSelected() >= 0) - { - mBuyShopItems->del(mBuyShopItemList->getSelected()); - if (isShopEmpty() && player_node) - player_node->updateStatus(); - } - else if (eventId == "delete sell" && mSellShopItemList - && mSellShopItemList->getSelected() >= 0) - { - mSellShopItems->del(mSellShopItemList->getSelected()); - if (isShopEmpty() && player_node) - player_node->updateStatus(); - } - else if (eventId == "announce buy" && mBuyShopItems - && mBuyShopItems->getNumberOfElements() > 0) - { - announce(mBuyShopItems, BUY); - } - else if (eventId == "announce sell" && mSellShopItems - && mSellShopItems->getNumberOfElements() > 0) - { - announce(mSellShopItems, SELL); - } - else if (eventId == "auction buy" && mBuyShopItems - && mBuyShopItems->getNumberOfElements() > 0) - { - Net::getChatHandler()->privateMessage("AuctionBot", "!pull4144 seek"); - } - else if (eventId == "auction sell" && mSellShopItems - && mSellShopItems->getNumberOfElements() > 0) - { - Net::getChatHandler()->privateMessage("AuctionBot", "!pull4144 offer"); - } - - if (mSelectedItem < 1) - return; - - const Inventory *const inv = PlayerInfo::getInventory(); - if (!inv) - return; - - // +++ need support for colors - Item *const item = inv->findItem(mSelectedItem, 0); - if (item) - { - if (eventId == "add buy") - { - ItemAmountWindow::showWindow(ItemAmountWindow::ShopBuyAdd, - this, item, sumAmount(item)); - } - else if (eventId == "add sell") - { - ItemAmountWindow::showWindow(ItemAmountWindow::ShopSellAdd, - this, item, sumAmount(item)); - } - } -} - -void ShopWindow::startTrade() -{ - if (!actorSpriteManager || !tradeWindow) - return; - - const Being *const being = actorSpriteManager->findBeingByName( - mTradeNick, Being::PLAYER); - tradeWindow->clear(); - if (mTradeMoney) - { - tradeWindow->addAutoMoney(mTradeNick, mTradeMoney); - } - else - { - tradeWindow->addAutoItem(mTradeNick, mTradeItem, - mTradeItem->getQuantity()); - } - Net::getTradeHandler()->request(being); - tradePartnerName = mTradeNick; - mTradeNick.clear(); -} - -void ShopWindow::valueChanged(const gcn::SelectionEvent &event A_UNUSED) -{ - updateButtonsAndLabels(); -} - -void ShopWindow::updateButtonsAndLabels() -{ - mBuyAddButton->setEnabled(mSelectedItem != -1); - mSellAddButton->setEnabled(mSelectedItem != -1); - mBuyDeleteButton->setEnabled( - mBuyShopItemList->getSelected() != -1 - && mBuyShopItems->getNumberOfElements() > 0); - mSellDeleteButton->setEnabled( - mSellShopItemList->getSelected() != -1 - && mSellShopItems->getNumberOfElements() > 0); -} - -void ShopWindow::setVisible(bool visible) -{ - Window::setVisible(visible); -} - -void ShopWindow::addBuyItem(const Item *const item, const int amount, - const int price) -{ - if (!mBuyShopItems || !item) - return; - const bool emp = isShopEmpty(); - mBuyShopItems->addItemNoDup(item->getId(), - item->getColor(), amount, price); - if (emp && player_node) - player_node->updateStatus(); - - updateButtonsAndLabels(); -} - -void ShopWindow::addSellItem(const Item *const item, const int amount, - const int price) -{ - if (!mBuyShopItems || !item) - return; - const bool emp = isShopEmpty(); - mSellShopItems->addItemNoDup(item->getId(), - item->getColor(), amount, price); - if (emp && player_node) - player_node->updateStatus(); - - updateButtonsAndLabels(); -} - -void ShopWindow::loadList() -{ - if (!mBuyShopItems || !mSellShopItems) - return; - - std::ifstream shopFile; - struct stat statbuf; - - mBuyShopItems->clear(); - mSellShopItems->clear(); - - const std::string shopListName = client->getServerConfigDirectory() - + "/shoplist.txt"; - - if (!stat(shopListName.c_str(), &statbuf) && S_ISREG(statbuf.st_mode)) - { - shopFile.open(shopListName.c_str(), std::ios::in); - if (!shopFile.is_open()) - { - shopFile.close(); - return; - } - char line[101]; - while (shopFile.getline(line, 100)) - { - std::string buf; - const std::string str = line; - if (!str.empty()) - { - std::vector tokens; - std::stringstream ss(str); - - while (ss >> buf) - tokens.push_back(atoi(buf.c_str())); - - if (tokens.size() == 5 && tokens[0]) - { - // +++ need impliment colors? - if (tokens[1] && tokens[2] && mBuyShopItems) - { - mBuyShopItems->addItem( - tokens[0], 1, tokens[1], tokens[2]); - } - if (tokens[3] && tokens[4] && mSellShopItems) - { - mSellShopItems->addItem( - tokens[0], 1, tokens[3], tokens[4]); - } - } - } - } - shopFile.close(); - } -} - -void ShopWindow::saveList() const -{ - if (!mBuyShopItems || !mSellShopItems) - return; - - std::ofstream shopFile; - const std::string shopListName = client->getServerConfigDirectory() - + "/shoplist.txt"; - std::map mapItems; - - shopFile.open(shopListName.c_str(), std::ios::binary); - if (!shopFile.is_open()) - { - logger->log1("Unable to open shoplist.txt for writing"); - return; - } - - std::vector items = mBuyShopItems->items(); - FOR_EACH (std::vector::const_iterator, it, items) - { - ShopItem *const item = *(it); - if (item) - mapItems[item->getId()] = item; - } - - items = mSellShopItems->items(); - FOR_EACH (std::vector::const_iterator, it, items) - { - if (!(*it)) - continue; - const ShopItem *const sellItem = *(it); - const ShopItem *const buyItem = mapItems[sellItem->getId()]; - - shopFile << sellItem->getId(); - if (buyItem) - { - shopFile << strprintf(" %d %d ", buyItem->getQuantity(), - buyItem->getPrice()); - mapItems.erase(sellItem->getId()); - } - else - { - shopFile << " 0 0 "; - } - - shopFile << strprintf("%d %d", sellItem->getQuantity(), - sellItem->getPrice()) << std::endl; - } - - for (std::map::const_iterator mapIt = mapItems.begin(), - mapIt_end = mapItems.end(); mapIt != mapIt_end; ++mapIt) - { - const ShopItem *const buyItem = (*mapIt).second; - if (buyItem) - { - shopFile << buyItem->getId(); - shopFile << strprintf(" %d %d ", buyItem->getQuantity(), - buyItem->getPrice()); - shopFile << "0 0" << std::endl; - } - } - - shopFile.close(); -} - -void ShopWindow::announce(ShopItems *const list, const int mode) -{ - if (!list) - return; - - std::string data("\302\202"); - if (mode == BUY) - data.append("Buy "); - else - data.append("Sell "); - - if (mAnnonceTime && (mAnnonceTime + (2 * 60) > cur_time - || mAnnonceTime > cur_time)) - { - return; - } - - mAnnonceTime = cur_time; - if (mBuyAnnounceButton) - mBuyAnnounceButton->setEnabled(false); - if (mSellAnnounceButton) - mSellAnnounceButton->setEnabled(false); - - std::vector items = list->items(); - - FOR_EACH (std::vector::const_iterator, it, items) - { - const ShopItem *const item = *(it); - if (item->getQuantity() > 1) - { - if (mAnnounceLinks->isSelected()) - { - data.append(strprintf("[@@%d|%s@@] (%dGP) %d, ", item->getId(), - item->getInfo().getName().c_str(), - item->getPrice(), item->getQuantity())); - } - else - { - data.append(strprintf("%s (%dGP) %d, ", - item->getInfo().getName().c_str(), - item->getPrice(), item->getQuantity())); - } - } - else - { - if (mAnnounceLinks->isSelected()) - { - data.append(strprintf("[@@%d|%s@@] (%dGP), ", item->getId(), - item->getInfo().getName().c_str(), item->getPrice())); - } - else - { - data.append(strprintf("%s (%dGP), ", - item->getInfo().getName().c_str(), item->getPrice())); - } - } - } - - Net::getChatHandler()->talk(data, GENERAL_CHANNEL); -} - -void ShopWindow::giveList(const std::string &nick, const int mode) -{ - if (!checkFloodCounter(mLastRequestTimeList)) - return; - - std::string data("\302\202"); - - ShopItems *list; - if (mode == BUY) - { - list = mBuyShopItems; - data.append("S1"); - } - else - { - list = mSellShopItems; - data.append("B1"); - } - if (!list) - return; - - const Inventory *const inv = PlayerInfo::getInventory(); - if (!inv) - return; - - std::vector items = list->items(); - - FOR_EACH (std::vector::const_iterator, it, items) - { - const ShopItem *const item = *(it); - if (!item) - continue; - - if (mode == SELL) - { - // +++ need support for colors - const Item *const item2 = inv->findItem(item->getId(), 0); - if (item2) - { - int amount = item->getQuantity(); - if (item2->getQuantity() < amount) - amount = item2->getQuantity(); - - if (amount) - { - data.append(strprintf("%s%s%s", - encodeStr(item->getId(), 2).c_str(), - encodeStr(item->getPrice(), 4).c_str(), - encodeStr(amount, 3).c_str())); - } - } - } - else - { - int amount = item->getQuantity(); - if (item->getPrice() * amount > PlayerInfo::getAttribute( - PlayerInfo::MONEY)) - { - amount = PlayerInfo::getAttribute(PlayerInfo::MONEY) - / item->getPrice(); - } - - if (amount > 0) - { - data.append(strprintf("%s%s%s", - encodeStr(item->getId(), 2).c_str(), - encodeStr(item->getPrice(), 4).c_str(), - encodeStr(amount, 3).c_str())); - } - } - } - sendMessage(nick, data, true); -} - -void ShopWindow::sendMessage(const std::string &nick, - std::string data, const bool random) -{ - if (!chatWindow) - return; - - if (random) - { - mRandCounter ++; - if (mRandCounter > 200) - mRandCounter = 0; - data.append(encodeStr(mRandCounter, 2)); - } - - if (config.getBoolValue("hideShopMessages")) - Net::getChatHandler()->privateMessage(nick, data); - else if (chatWindow) - chatWindow->addWhisper(nick, data, BY_PLAYER); -} - -void ShopWindow::showList(const std::string &nick, std::string data) const -{ - BuyDialog *buyDialog = nullptr; - SellDialog *sellDialog = nullptr; - if (data.find("B1") == 0) - { - data = data.substr(2); - buyDialog = new BuyDialog(nick); - } - else if (data.find("S1") == 0) - { - data = data.substr(2); - sellDialog = new SellDialog(nick); - } - else - { - return; - } - - const Inventory *const inv = PlayerInfo::getInventory(); - if (!inv) - return; - - if (buyDialog) - buyDialog->setMoney(PlayerInfo::getAttribute(PlayerInfo::MONEY)); - if (sellDialog) - sellDialog->setMoney(PlayerInfo::getAttribute(PlayerInfo::MONEY)); - - for (unsigned f = 0; f < data.length(); f += 9) - { - if (f + 9 > data.length()) - break; - - const int id = decodeStr(data.substr(f, 2)); - const int price = decodeStr(data.substr(f + 2, 4)); - int amount = decodeStr(data.substr(f + 6, 3)); - // +++ need impliment colors? - if (buyDialog && amount > 0) - buyDialog->addItem(id, 1, amount, price); - if (sellDialog) - { - // +++ need support for colors - const Item *const item = inv->findItem(id, 0); - if (item) - { - if (item->getQuantity() < amount) - amount = item->getQuantity(); - if (amount > 0) - sellDialog->addItem(id, 1, amount, price); - else - sellDialog->addItem(id, 1, -1, price); - } - } - } -} - -void ShopWindow::processRequest(const std::string &nick, std::string data, - const int mode) -{ - if (!player_node || !mTradeNick.empty() || PlayerInfo::isTrading() - || !actorSpriteManager - || !actorSpriteManager->findBeingByName(nick, Being::PLAYER)) - { - return; - } - - const Inventory *const inv = PlayerInfo::getInventory(); - if (!inv) - return; - - const size_t idx = data.find(" "); - if (idx == std::string::npos) - return; - - if (!checkFloodCounter(mLastRequestTimeItem)) - return; - - if (!mTradeNick.empty()) - { - sendMessage(nick, "error: player busy ", true); - return; - } - - data = data.substr(idx + 1); - - std::string part1; - std::string part2; - std::string part3; - std::stringstream ss(data); - std::string msg; - int id; - int price; - int amount; - - if (!(ss >> part1)) - return; - - if (!(ss >> part2)) - return; - - if (!(ss >> part3)) - return; - - id = atoi(part1.c_str()); - price = atoi(part2.c_str()); - amount = atoi(part3.c_str()); - - delete mTradeItem; - // +++ need impliment colors? - mTradeItem = new ShopItem(-1, id, 1, amount, price); - - if (mode == BUY) - { - // +++ need support for colors - const Item *const item2 = inv->findItem(mTradeItem->getId(), 0); - if (!item2 || item2->getQuantity() < amount - || !findShopItem(mTradeItem, SELL)) - { - sendMessage(nick, "error: Can't sell this item ", true); - return; - } - msg = "buy"; - mTradeMoney = 0; - } - else - { - if (!findShopItem(mTradeItem, BUY)) - { - sendMessage(nick, "error: Can't buy this item ", true); - return; - } - msg = "sell"; - mTradeMoney = mTradeItem->getPrice() * mTradeItem->getQuantity(); - } - - mTradeNick = nick; - - if (config.getBoolValue("autoShop")) - { - soundManager.playGuiSound(SOUND_TRADE); - startTrade(); - } - else - { - ConfirmDialog *const confirmDlg = new ConfirmDialog - // TRANSLATORS: shop window dialog - (_("Request for Trade"), strprintf(_("%s wants to %s %s do you " - "accept?"), nick.c_str(), msg.c_str(), - mTradeItem->getInfo().getName().c_str()), SOUND_REQUEST, true); - confirmDlg->addActionListener(this); - } -} - -void ShopWindow::updateTimes() -{ - BLOCK_START("ShopWindow::updateTimes") - if (mAnnonceTime + (2 * 60) < cur_time - || mAnnonceTime > cur_time) - { - mBuyAnnounceButton->setEnabled(true); - mSellAnnounceButton->setEnabled(true); - } - BLOCK_END("ShopWindow::updateTimes") -} - -bool ShopWindow::checkFloodCounter(int &counterTime) -{ - if (!counterTime || counterTime > cur_time) - counterTime = cur_time; - else if (counterTime + 10 > cur_time) - return false; - - counterTime = cur_time; - return true; -} - -bool ShopWindow::findShopItem(const ShopItem *const shopItem, - const int mode) const -{ - if (!shopItem) - return false; - - std::vector items; - if (mode == SELL) - { - if (!mSellShopItems) - return false; - items = mSellShopItems->items(); - } - else - { - if (!mBuyShopItems) - return false; - items = mBuyShopItems->items(); - } - - FOR_EACH (std::vector::const_iterator, it, items) - { - const ShopItem *const item = *(it); - if (!item) - continue; - - if (item->getId() == shopItem->getId() - && item->getPrice() == shopItem->getPrice() - && item->getQuantity() >= shopItem->getQuantity()) - { - return true; - } - } - return false; -} - -int ShopWindow::sumAmount(const Item *const shopItem) -{ - if (!player_node || !shopItem) - return 0; - - const Inventory *const inv = PlayerInfo::getInventory(); - if (!inv) - return 0; - int sum = 0; - - for (unsigned f = 0; f < inv->getSize(); f ++) - { - const Item *const item = inv->getItem(f); - if (item && item->getId() == shopItem->getId()) - sum += item->getQuantity(); - } - return sum; -} - -bool ShopWindow::isShopEmpty() const -{ - if (!mBuyShopItems || !mSellShopItems) - return true; - if (mBuyShopItems->empty() && mSellShopItems->empty()) - return true; - return false; -} diff --git a/src/gui/shopwindow.h b/src/gui/shopwindow.h deleted file mode 100644 index 7e33416e9..000000000 --- a/src/gui/shopwindow.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_SHOPWINDOW_H -#define GUI_SHOPWINDOW_H - -#include "gui/widgets/window.h" - -#include -#include - -class Button; -class CheckBox; -class Item; -class Label; -class ScrollArea; -class ShopItem; -class ShopItems; -class ShopListBox; - -/** - * The buy dialog. - * - * \ingroup Interface - */ -class ShopWindow final : public Window, public gcn::ActionListener, - public gcn::SelectionListener -{ - public: - enum ShopMode - { - BUY = 0, - SELL = 1 - }; - - /** - * Constructor. - * - * @see Window::Window - */ - ShopWindow(); - - A_DELETE_COPY(ShopWindow) - - /** - * Destructor - */ - ~ShopWindow(); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - /** - * Updates the labels according to the selected item. - */ - void valueChanged(const gcn::SelectionEvent &event) override; - - /** - * Updates the state of buttons and labels. - */ - void updateButtonsAndLabels(); - - /** - * Sets the visibility of this window. - */ - void setVisible(bool visible) override; - - /** - * Returns true if any instances exist. - */ - static bool isActive() A_WARN_UNUSED - { return !instances.empty(); } - - void setItemSelected(const int id) - { mSelectedItem = id; updateButtonsAndLabels(); } - - void addBuyItem(const Item *const item, const int amount, - const int price); - - void addSellItem(const Item *const item, const int amount, - const int price); - - void loadList(); - - void saveList() const; - - void announce(ShopItems *const list, const int mode); - - void giveList(const std::string &nick, const int mode); - - void setAcceptPlayer(const std::string &name) - { mAcceptPlayer = name; } - - const std::string &getAcceptPlayer() const A_WARN_UNUSED - { return mAcceptPlayer; } - - void sendMessage(const std::string &nick, std::string data, - const bool random = false); - - void showList(const std::string &nick, std::string data) const; - - void processRequest(const std::string &nick, std::string data, - const int mode); - - bool findShopItem(const ShopItem *const shopItem, - const int mode) const A_WARN_UNUSED; - - static int sumAmount(const Item *const shopItem) A_WARN_UNUSED; - - void updateTimes(); - - static bool checkFloodCounter(int &counterTime) A_WARN_UNUSED; - - bool isShopEmpty() const A_WARN_UNUSED; - - private: - void startTrade(); - - typedef std::list DialogList; - static DialogList instances; - - Button *mCloseButton; - - ShopItems *mBuyShopItems; - ShopItems *mSellShopItems; - - ShopListBox *mBuyShopItemList; - ShopListBox *mSellShopItemList; - ScrollArea *mBuyScrollArea; - ScrollArea *mSellScrollArea; - Label *mBuyLabel; - Label *mSellLabel; - Button *mBuyAddButton; - Button *mBuyDeleteButton; - Button *mBuyAnnounceButton; - Button *mBuyAuctionButton; - Button *mSellAddButton; - Button *mSellDeleteButton; - Button *mSellAnnounceButton; - Button *mSellAuctionButton; - CheckBox *mAnnounceLinks; - - int mSelectedItem; - int mAnnonceTime; - int mLastRequestTimeList; - int mLastRequestTimeItem; - int mRandCounter; - std::string mAcceptPlayer; - ShopItem *mTradeItem; - std::string mTradeNick; - int mTradeMoney; - int mAnnounceCounter[2]; -}; - -extern ShopWindow *shopWindow; - -#endif // GUI_SHOPWINDOW_H diff --git a/src/gui/shortcutwindow.cpp b/src/gui/shortcutwindow.cpp deleted file mode 100644 index 53aa18ece..000000000 --- a/src/gui/shortcutwindow.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2007-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/shortcutwindow.h" - -#include "gui/setup.h" - -#include "gui/widgets/layout.h" -#include "gui/widgets/scrollarea.h" -#include "gui/widgets/shortcutcontainer.h" -#include "gui/widgets/tab.h" - -#include "debug.h" - -static const int SCROLL_PADDING = 0; - -int ShortcutWindow::mBoxesWidth = 0; - -class ShortcutTab final : public Tab -{ - public: - ShortcutTab(const Widget2 *const widget, - std::string name, ShortcutContainer *const content) : - Tab(widget), - mContent(content) - { - setCaption(name); - } - - A_DELETE_COPY(ShortcutTab) - - ShortcutContainer* mContent; -}; - -ShortcutWindow::ShortcutWindow(const std::string &title, - ShortcutContainer *const content, - const std::string &skinFile, - int width, int height) : - Window("Window", false, nullptr, skinFile), - mItems(content), - mScrollArea(new ScrollArea(mItems, false)), - mTabs(nullptr), - mPages() -{ - setWindowName(title); - setTitleBarHeight(getPadding() + getTitlePadding()); - - setShowTitle(false); - setResizable(true); - setDefaultVisible(false); - setSaveVisible(true); - - mDragOffsetX = 0; - mDragOffsetY = 0; - - content->setWidget2(this); - if (setupWindow) - setupWindow->registerWindowForReset(this); - - const int border = SCROLL_PADDING * 2 + getPadding() * 2; - setMinWidth(mItems->getBoxWidth() + border); - setMinHeight(mItems->getBoxHeight() + border); - setMaxWidth(mItems->getBoxWidth() * mItems->getMaxItems() + border); - setMaxHeight(mItems->getBoxHeight() * mItems->getMaxItems() + border); - - if (width == 0) - width = mItems->getBoxWidth() + border; - if (height == 0) - height = (mItems->getBoxHeight() * mItems->getMaxItems()) + border; - - setDefaultSize(width, height, ImageRect::LOWER_RIGHT); - - mBoxesWidth += mItems->getBoxWidth() + border; - - mScrollArea->setPosition(SCROLL_PADDING, SCROLL_PADDING); - mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - - place(0, 0, mScrollArea, 5, 5).setPadding(0); - - Layout &layout = getLayout(); - layout.setRowHeight(0, Layout::AUTO_SET); - layout.setMargin(0); - - loadWindowState(); - enableVisibleSound(true); -} - -ShortcutWindow::ShortcutWindow(const std::string &title, - const std::string &skinFile, - const int width, const int height) : - Window("Window", false, nullptr, skinFile), - mItems(nullptr), - mScrollArea(nullptr), - mTabs(new TabbedArea(this)), - mPages() -{ - setWindowName(title); - setTitleBarHeight(getPadding() + getTitlePadding()); - setShowTitle(false); - setResizable(true); - setDefaultVisible(false); - setSaveVisible(true); - - mDragOffsetX = 0; - mDragOffsetY = 0; - - if (setupWindow) - setupWindow->registerWindowForReset(this); - - const int border = SCROLL_PADDING * 2 + getPadding() * 2; - - if (width && height) - setDefaultSize(width, height, ImageRect::LOWER_RIGHT); - - setMinWidth(32 + border); - setMinHeight(32 + border); - - place(0, 0, mTabs, 5, 5); - - Layout &layout = getLayout(); - layout.setRowHeight(0, Layout::AUTO_SET); - layout.setMargin(0); - - loadWindowState(); - enableVisibleSound(true); -} - -ShortcutWindow::~ShortcutWindow() -{ - if (mTabs) - mTabs->removeAll(); - delete mTabs; - mTabs = nullptr; - delete mItems; - mItems = nullptr; -} - -void ShortcutWindow::addTab(const std::string &name, - ShortcutContainer *const content) -{ - ScrollArea *const scroll = new ScrollArea(content, false); - scroll->setPosition(SCROLL_PADDING, SCROLL_PADDING); - scroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - content->setWidget2(this); - Tab *const tab = new ShortcutTab(this, name, content); - mTabs->addTab(tab, scroll); - mPages.push_back(content); -} - -int ShortcutWindow::getTabIndex() const -{ - if (!mTabs) - return 0; - return mTabs->getSelectedTabIndex(); -} - -void ShortcutWindow::widgetHidden(const gcn::Event &event) -{ - if (mItems) - mItems->widgetHidden(event); - if (mTabs) - { - ScrollArea *const scroll = static_cast( - mTabs->getCurrentWidget()); - if (scroll) - { - ShortcutContainer *const content = static_cast( - scroll->getContent()); - - if (content) - content->widgetHidden(event); - } - } -} - -void ShortcutWindow::mousePressed(gcn::MouseEvent &event) -{ - Window::mousePressed(event); - - if (event.isConsumed()) - return; - - if (event.getButton() == gcn::MouseEvent::LEFT) - { - mDragOffsetX = event.getX(); - mDragOffsetY = event.getY(); - } -} - -void ShortcutWindow::mouseDragged(gcn::MouseEvent &event) -{ - Window::mouseDragged(event); - - if (event.isConsumed()) - return; - - if (canMove() && isMovable() && mMoved) - { - int newX = std::max(0, getX() + event.getX() - mDragOffsetX); - int newY = std::max(0, getY() + event.getY() - mDragOffsetY); - newX = std::min(mainGraphics->mWidth - getWidth(), newX); - newY = std::min(mainGraphics->mHeight - getHeight(), newY); - setPosition(newX, newY); - } -} - -void ShortcutWindow::widgetMoved(const gcn::Event& event) -{ - Window::widgetMoved(event); - if (mItems) - mItems->setRedraw(true); - FOR_EACH (std::vector::iterator, it, mPages) - (*it)->setRedraw(true); -} - -#ifdef USE_PROFILER -void ShortcutWindow::logicChildren() -{ - BLOCK_START("ShortcutWindow::logicChildren") - BasicContainer::logicChildren(); - BLOCK_END("ShortcutWindow::logicChildren") -} -#endif diff --git a/src/gui/shortcutwindow.h b/src/gui/shortcutwindow.h deleted file mode 100644 index cc2ba97b0..000000000 --- a/src/gui/shortcutwindow.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2007-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_SHORTCUTWINDOW_H -#define GUI_SHORTCUTWINDOW_H - -#include "gui/widgets/window.h" - -class ScrollArea; -class ShortcutContainer; -class TabbedArea; - -/** - * A window around a ShortcutContainer. - * - * \ingroup Interface - */ -class ShortcutWindow final : public Window -{ - public: - /** - * Constructor. - */ - ShortcutWindow(const std::string &title, - ShortcutContainer *const content, - const std::string &skinFile = "", - int width = 0, int height = 0); - - ShortcutWindow(const std::string &title, - const std::string &skinFile = "", - const int width = 0, const int height = 0); - - A_DELETE_COPY(ShortcutWindow) - - /** - * Destructor. - */ - ~ShortcutWindow(); - - void addTab(const std::string &name, ShortcutContainer *const content); - - int getTabIndex() const A_WARN_UNUSED; - - void widgetHidden(const gcn::Event &event) override; - - void widgetMoved(const gcn::Event& event) override; - - void mousePressed(gcn::MouseEvent &event) override; - - void mouseDragged(gcn::MouseEvent &event) override; - -#ifdef USE_PROFILER - void logicChildren(); -#endif - - private: - ShortcutWindow(); - ShortcutContainer *mItems; - - ScrollArea *mScrollArea; - TabbedArea *mTabs; - std::vector mPages; - - static int mBoxesWidth; -}; - -extern ShortcutWindow *itemShortcutWindow; -extern ShortcutWindow *emoteShortcutWindow; -extern ShortcutWindow *dropShortcutWindow; - -#endif // GUI_SHORTCUTWINDOW_H diff --git a/src/gui/skilldialog.cpp b/src/gui/skilldialog.cpp deleted file mode 100644 index 94ac10fc6..000000000 --- a/src/gui/skilldialog.cpp +++ /dev/null @@ -1,721 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/skilldialog.h" - -#include "configuration.h" -#include "dragdrop.h" -#include "effectmanager.h" -#include "itemshortcut.h" - -#include "being/localplayer.h" - -#include "gui/setup.h" -#include "gui/shortcutwindow.h" -#include "gui/textpopup.h" -#include "gui/viewport.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/label.h" -#include "gui/widgets/listbox.h" -#include "gui/widgets/scrollarea.h" -#include "gui/widgets/skillmodel.h" -#include "gui/widgets/tab.h" -#include "gui/widgets/tabbedarea.h" - -#include "net/net.h" -#include "net/playerhandler.h" -#include "net/skillhandler.h" - -#include "utils/dtor.h" -#include "utils/gettext.h" - -#include - -#include "debug.h" - -class SkillListBox final : public ListBox -{ - public: - SkillListBox(const Widget2 *const widget, SkillModel *const model) : - ListBox(widget, model, "skilllistbox.xml"), - mModel(model), - mPopup(new TextPopup), - mHighlightColor(getThemeColor(Theme::HIGHLIGHT)), - mTextColor(getThemeColor(Theme::TEXT)), - mTextColor2(getThemeColor(Theme::TEXT_OUTLINE)), - mTextPadding(mSkin ? mSkin->getOption("textPadding", 34) : 34), - mSpacing(mSkin ? mSkin->getOption("spacing", 0) : 0), - mRowHeight(getFont()->getHeight() * 2 + mSpacing + 2 * mPadding), - mSkillClicked(false) - { - if (mRowHeight < 34) - mRowHeight = 34; - } - - A_DELETE_COPY(SkillListBox) - - ~SkillListBox() - { - delete mModel; - mModel = nullptr; - delete mPopup; - mPopup = nullptr; - } - - SkillInfo *getSelectedInfo() const - { - const int selected = getSelected(); - if (!mListModel || selected < 0 - || selected > mListModel->getNumberOfElements()) - { - return nullptr; - } - - return static_cast(mListModel)->getSkillAt(selected); - } - - void draw(gcn::Graphics *gcnGraphics) override - { - if (!mListModel) - return; - - SkillModel *const model = static_cast(mListModel); - updateAlpha(); - Graphics *const graphics = static_cast( - gcnGraphics); - - mHighlightColor.a = static_cast(mAlpha * 255.0F); - graphics->setColor(mHighlightColor); - - // Draw filled rectangle around the selected list element - if (mSelected >= 0) - { - graphics->fillRectangle(gcn::Rectangle(mPadding, getRowHeight() - * mSelected + mPadding, getWidth() - 2 * mPadding, - getRowHeight())); - } - - // Draw the list elements - graphics->setColorAll(mTextColor, mTextColor2); - gcn::Font *const font = getFont(); - const int space = font->getHeight() + mSpacing; - const int width2 = getWidth() - mPadding; - for (int i = 0, y = 1; - i < model->getNumberOfElements(); - ++i, y += getRowHeight()) - { - SkillInfo *const e = model->getSkillAt(i); - if (e) - { - const SkillData *const data = e->data; - const int yPad = y + mPadding; - const std::string &description = data->description; - graphics->drawImage(data->icon, mPadding, yPad); - font->drawString(graphics, data->name, mTextPadding, yPad); - if (!description.empty()) - { - font->drawString(graphics, description, - mTextPadding, yPad + space); - } - - if (e->skillLevelWidth < 0) - { - // Add one for padding - e->skillLevelWidth = font->getWidth(e->skillLevel) + 1; - } - - font->drawString(graphics, e->skillLevel, width2 - - e->skillLevelWidth, yPad); - } - } - } - - unsigned int getRowHeight() const override - { return mRowHeight; } - - const SkillInfo *getSkillByEvent(const gcn::MouseEvent &event) const - { - const int y = (event.getY() + mPadding) / getRowHeight(); - if (!mModel || y >= mModel->getNumberOfElements()) - return nullptr; - const SkillInfo *const skill = mModel->getSkillAt(y); - if (!skill) - return nullptr; - return skill; - } - - void mouseMoved(gcn::MouseEvent &event) override - { - ListBox::mouseMoved(event); - if (!viewport || !dragDrop.isEmpty()) - return; - - const SkillInfo *const skill = getSkillByEvent(event); - if (!skill) - return; - - mPopup->show(viewport->getMouseX(), viewport->getMouseY(), - skill->data->dispName, skill->data->description); - } - - void mouseDragged(gcn::MouseEvent &event) - { - if (event.getButton() == gcn::MouseEvent::LEFT) - { - if (dragDrop.isEmpty()) - { - if (mSkillClicked) - { - mSkillClicked = false; - const SkillInfo *const skill = getSkillByEvent(event); - if (!skill) - return; - dragDrop.dragSkill(skill, DRAGDROP_SOURCE_SKILLS); - dragDrop.setItem(skill->id + SKILL_MIN_ID); - } - ListBox::mouseDragged(event); - } - } - else - { - ListBox::mouseDragged(event); - } - } - - void mousePressed(gcn::MouseEvent &event) - { - ListBox::mousePressed(event); - if (event.getButton() == gcn::MouseEvent::LEFT) - { - const SkillInfo *const skill = getSkillByEvent(event); - if (!skill) - return; - mSkillClicked = true; - } - } - - void mouseReleased(gcn::MouseEvent &event) - { - ListBox::mouseReleased(event); - } - - void mouseExited(gcn::MouseEvent &event A_UNUSED) override - { - mPopup->hide(); - } - - private: - SkillModel *mModel; - TextPopup *mPopup; - gcn::Color mHighlightColor; - gcn::Color mTextColor; - gcn::Color mTextColor2; - int mTextPadding; - int mSpacing; - int mRowHeight; - bool mSkillClicked; -}; - -class SkillTab final : public Tab -{ - public: - SkillTab(const Widget2 *const widget, - const std::string &name, SkillListBox *const listBox) : - Tab(widget), - mListBox(listBox) - { - setCaption(name); - } - - A_DELETE_COPY(SkillTab) - - ~SkillTab() - { - delete mListBox; - mListBox = nullptr; - } - - SkillInfo *getSelectedInfo() const - { - if (mListBox) - return mListBox->getSelectedInfo(); - else - return nullptr; - } - - protected: - void setCurrent() override - { - if (skillDialog) - skillDialog->updateTabSelection(); - } - - private: - SkillListBox *mListBox; -}; - -SkillDialog::SkillDialog() : - // TRANSLATORS: skills dialog name - Window(_("Skills"), false, nullptr, "skills.xml"), - gcn::ActionListener(), - mSkills(), - mTabs(new TabbedArea(this)), - mDeleteTabs(), - mPointsLabel(new Label(this, "0")), - // TRANSLATORS: skills dialog button - mUseButton(new Button(this, _("Use"), "use", this)), - // TRANSLATORS: skills dialog button - mIncreaseButton(new Button(this, _("Up"), "inc", this)), - mDefaultModel(nullptr) -{ - setWindowName("Skills"); - setCloseButton(true); - setResizable(true); - setSaveVisible(true); - setStickyButtonLock(true); - setDefaultSize(windowContainer->getWidth() - 280, 30, 275, 425); - if (setupWindow) - setupWindow->registerWindowForReset(this); - - mUseButton->setEnabled(false); - mIncreaseButton->setEnabled(false); - - place(0, 0, mTabs, 5, 5); - place(0, 5, mPointsLabel, 4); - place(3, 5, mUseButton); - place(4, 5, mIncreaseButton); - - setLocationRelativeTo(getParent()); - loadWindowState(); - enableVisibleSound(true); -} - -SkillDialog::~SkillDialog() -{ - clearSkills(); -} - -void SkillDialog::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "inc") - { - const SkillTab *const tab = static_cast( - mTabs->getSelectedTab()); - if (tab) - { - if (const SkillInfo *const info = tab->getSelectedInfo()) - Net::getPlayerHandler()->increaseSkill(info->id); - } - } - else if (eventId == "sel") - { - const SkillTab *const tab = static_cast( - mTabs->getSelectedTab()); - if (tab) - { - if (const SkillInfo *const info = tab->getSelectedInfo()) - { - mUseButton->setEnabled(info->range > 0); - mIncreaseButton->setEnabled(info->id < SKILL_VAR_MIN_ID); - const int num = itemShortcutWindow->getTabIndex(); - if (num >= 0 && num < static_cast(SHORTCUT_TABS) - && itemShortcut[num]) - { - itemShortcut[num]->setItemSelected( - info->id + SKILL_MIN_ID); - } - } - else - { - mUseButton->setEnabled(false); - mIncreaseButton->setEnabled(false); - } - } - } - else if (eventId == "use") - { - const SkillTab *const tab = static_cast( - mTabs->getSelectedTab()); - if (tab) - { - const SkillInfo *const info = tab->getSelectedInfo(); - if (info && player_node && player_node->getTarget()) - { - const Being *const being = player_node->getTarget(); - if (being) - { - Net::getSkillHandler()->useBeing(info->level, - info->id, being->getId()); - } - } - } - } - else if (eventId == "close") - { - setVisible(false); - } -} - -std::string SkillDialog::update(const int id) -{ - const SkillMap::const_iterator i = mSkills.find(id); - - if (i != mSkills.end()) - { - SkillInfo *const info = i->second; - if (info) - { - info->update(); - return info->data->name; - } - } - - return std::string(); -} - -void SkillDialog::update() -{ - // TRANSLATORS: skills dialog label - mPointsLabel->setCaption(strprintf(_("Skill points available: %d"), - PlayerInfo::getAttribute(PlayerInfo::SKILL_POINTS))); - mPointsLabel->adjustSize(); - - FOR_EACH (SkillMap::const_iterator, it, mSkills) - { - if ((*it).second && (*it).second->modifiable) - (*it).second->update(); - } -} - -void SkillDialog::clearSkills() -{ - mTabs->removeAll(); - mDeleteTabs.clear(); - mDefaultModel = nullptr; - - delete_all(mSkills); - mSkills.clear(); -} - -void SkillDialog::loadSkills() -{ - clearSkills(); - - XML::Document doc(paths.getStringValue("skillsFile")); - XML::Document doc2(paths.getStringValue("skillsFile2")); - XmlNodePtr root = doc.rootNode(); - - int setCount = 0; - std::string setName; - ScrollArea *scroll; - SkillListBox *listbox; - SkillTab *tab; - - if (!root || !xmlNameEqual(root, "skills")) - root = doc2.rootNode(); - - if (!root || !xmlNameEqual(root, "skills")) - { - logger->log("Error loading skills"); - -#ifdef MANASERV_SUPPORT - if (Net::getNetworkType() != ServerInfo::MANASERV) -#endif - { - SkillModel *const model = new SkillModel(); - if (!mDefaultModel) - mDefaultModel = model; - - SkillInfo *const skill = new SkillInfo; - skill->id = 1; - // TRANSLATORS: skills dialog default skills tab - skill->data->name = _("basic"); - skill->data->description.clear(); - // TRANSLATORS: skills dialog default skill name - skill->data->dispName = _("basic, 1"); - skill->data->shortName = "bas"; - skill->data->setIcon(""); - skill->modifiable = true; - skill->visible = true; - skill->model = model; - skill->update(); - - model->addSkill(skill); - mSkills[1] = skill; - - model->updateVisibilities(); - - listbox = new SkillListBox(this, model); - listbox->setActionEventId("sel"); - listbox->addActionListener(this); - scroll = new ScrollArea(listbox, false); - scroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); - scroll->setVerticalScrollPolicy(ScrollArea::SHOW_ALWAYS); - - tab = new SkillTab(this, "Skills", listbox); - mDeleteTabs.push_back(tab); - - mTabs->addTab(tab, scroll); - - update(); - } - return; - } - - for_each_xml_child_node(set, root) - { - if (xmlNameEqual(set, "set")) - { - setCount++; - setName = XML::getProperty(set, "name", - // TRANSLATORS: skills dialog default skill tab - strprintf(_("Skill Set %d"), setCount)); - - SkillModel *const model = new SkillModel(); - if (!mDefaultModel) - mDefaultModel = model; - - for_each_xml_child_node(node, set) - { - if (xmlNameEqual(node, "skill")) - { - int id = XML::getIntProperty(node, "id", -1, -1, 1000000); - if (id == -1) - { - id = XML::getIntProperty(node, "var", -1, -1, 100000); - if (id == -1) - continue; - id += SKILL_VAR_MIN_ID; - } - - SkillInfo *skill = getSkill(id); - if (!skill) - { - skill = new SkillInfo; - skill->id = static_cast(id); - skill->modifiable = false; - skill->visible = false; - skill->model = model; - skill->update(); - model->addSkill(skill); - mSkills[id] = skill; - } - - std::string name = XML::langProperty(node, "name", - // TRANSLATORS: skills dialog. skill id - strprintf(_("Skill %d"), id)); - std::string icon = XML::getProperty(node, "icon", ""); - const int level = XML::getProperty(node, "level", 0); - SkillData *data = skill->getData(level); - if (!data) - data = new SkillData(); - - data->name = name; - data->setIcon(icon); - if (skill->id < SKILL_VAR_MIN_ID) - { - data->dispName = strprintf("%s, %u", - name.c_str(), skill->id); - } - else - { - data->dispName = strprintf("%s, (%u)", - name.c_str(), skill->id - SKILL_VAR_MIN_ID); - } - data->shortName = XML::langProperty(node, - "shortName", name.substr(0, 3)); - data->description = XML::langProperty( - node, "description", ""); - data->particle = XML::getProperty( - node, "particle", ""); - - data->soundHit.sound = XML::getProperty( - node, "soundHit", ""); - data->soundHit.delay = XML::getProperty( - node, "soundHitDelay", 0); - data->soundMiss.sound = XML::getProperty( - node, "soundMiss", ""); - data->soundMiss.delay = XML::getProperty( - node, "soundMissDelay", 0); - - skill->addData(level, data); - } - } - - model->updateVisibilities(); - - // possible leak listbox, scroll - listbox = new SkillListBox(this, model); - listbox->setActionEventId("sel"); - listbox->addActionListener(this); - scroll = new ScrollArea(listbox, false); - scroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); - scroll->setVerticalScrollPolicy(ScrollArea::SHOW_ALWAYS); - - tab = new SkillTab(this, setName, listbox); - mDeleteTabs.push_back(tab); - - mTabs->addTab(tab, scroll); - } - } - update(); -} - -bool SkillDialog::updateSkill(const int id, const int range, - const bool modifiable) -{ - const SkillMap::const_iterator it = mSkills.find(id); - - if (it != mSkills.end()) - { - SkillInfo *const info = it->second; - if (info) - { - info->modifiable = modifiable; - info->range = range; - info->update(); - } - return true; - } - return false; -} - -void SkillDialog::addSkill(const int id, const int level, const int range, - const bool modifiable) -{ - if (mDefaultModel) - { - SkillInfo *const skill = new SkillInfo; - skill->id = static_cast(id); - SkillData *const data = skill->data; - data->name = "Unknown skill Id: " + toString(id); - data->dispName = data->name; - data->description.clear(); - data->setIcon(""); - skill->modifiable = modifiable; - skill->visible = false; - skill->model = mDefaultModel; - skill->level = level; - // TRANSLATORS: skills dialog. skill level - skill->skillLevel = strprintf(_("Lvl: %d"), level); - skill->range = range; - skill->update(); - - mDefaultModel->addSkill(skill); - - mSkills[id] = skill; - mDefaultModel->updateVisibilities(); - } -} - -SkillInfo* SkillDialog::getSkill(const int id) const -{ - SkillMap::const_iterator it = mSkills.find(id); - if (it != mSkills.end()) - return (*it).second; - return nullptr; -} - -SkillInfo* SkillDialog::getSkillByItem(const int itemId) const -{ - SkillMap::const_iterator it = mSkills.find(itemId - SKILL_MIN_ID); - if (it != mSkills.end()) - return (*it).second; - return nullptr; -} - -void SkillDialog::widgetResized(const gcn::Event &event) -{ - Window::widgetResized(event); - - if (mTabs) - mTabs->adjustSize(); -} - -void SkillDialog::useItem(const int itemId) const -{ - const std::map::const_iterator - it = mSkills.find(itemId - SKILL_MIN_ID); - if (it == mSkills.end()) - return; - - const SkillInfo *const info = (*it).second; - if (info && player_node && player_node->getTarget()) - { - const Being *const being = player_node->getTarget(); - if (being) - { - Net::getSkillHandler()->useBeing(info->level, - info->id, being->getId()); - } - } -} - -void SkillDialog::updateTabSelection() -{ - const SkillTab *const tab = static_cast( - mTabs->getSelectedTab()); - if (tab) - { - if (const SkillInfo *const info = tab->getSelectedInfo()) - { - mUseButton->setEnabled(info->range > 0); - mIncreaseButton->setEnabled(info->id < SKILL_VAR_MIN_ID); - } - else - { - mUseButton->setEnabled(false); - } - } -} - -void SkillDialog::updateQuest(const int var, const int val) -{ - const int id = var + SKILL_VAR_MIN_ID; - const SkillMap::const_iterator it = mSkills.find(id); - - if (it != mSkills.end()) - { - SkillInfo *const info = it->second; - if (info) - { - PlayerInfo::setSkillLevel(id, val); - info->level = val; - info->update(); - } - } -} - -void SkillDialog::playUpdateEffect(const int id) const -{ - const int effectId = paths.getIntValue("skillLevelUpEffectId"); - if (!effectManager || effectId == -1) - return; - const SkillMap::const_iterator it = mSkills.find(id); - if (it != mSkills.end()) - { - if (it->second) - effectManager->trigger(effectId, player_node); - } -} diff --git a/src/gui/skilldialog.h b/src/gui/skilldialog.h deleted file mode 100644 index 9715a3bf3..000000000 --- a/src/gui/skilldialog.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_SKILLDIALOG_H -#define GUI_SKILLDIALOG_H - -#include "gui/widgets/window.h" - -#include - -const int SKILL_MIN_ID = 200000; -const unsigned int SKILL_VAR_MIN_ID = 1000000; - -class Button; -class Label; -class SkillModel; -class Tab; -class TabbedArea; - -struct SkillInfo; - -/** - * The skill dialog. - * - * \ingroup Interface - */ -class SkillDialog final : public Window, public gcn::ActionListener -{ - public: - SkillDialog(); - - A_DELETE_COPY(SkillDialog) - - ~SkillDialog(); - - /** - * Called when receiving actions from widget. - */ - void action(const gcn::ActionEvent &event) override; - - /** - * Update the given skill's display - */ - std::string update(const int id); - - /** - * Update other parts of the display - */ - void update(); - - void clearSkills(); - - void loadSkills(); - - bool updateSkill(const int id, const int range, const bool modifiable); - - void addSkill(const int id, const int level, const int range, - const bool modifiable); - - SkillInfo* getSkill(const int id) const A_WARN_UNUSED; - - SkillInfo* getSkillByItem(const int itemId) const A_WARN_UNUSED; - - bool hasSkills() const A_WARN_UNUSED - { return !mSkills.empty(); } - - void widgetResized(const gcn::Event &event) override; - - void useItem(const int itemId) const; - - void updateTabSelection(); - - void updateQuest(const int var, const int val); - - void playUpdateEffect(const int id) const; - - private: - typedef std::map SkillMap; - SkillMap mSkills; - TabbedArea *mTabs; - std::list mDeleteTabs; - Label *mPointsLabel; - Button *mUseButton; - Button *mIncreaseButton; - SkillModel *mDefaultModel; -}; - -extern SkillDialog *skillDialog; - -#endif // GUI_SKILLDIALOG_H diff --git a/src/gui/socialwindow.cpp b/src/gui/socialwindow.cpp deleted file mode 100644 index f8a1650a4..000000000 --- a/src/gui/socialwindow.cpp +++ /dev/null @@ -1,1894 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/socialwindow.h" - -#include "actorspritemanager.h" -#include "configuration.h" -#include "guild.h" -#include "guildmanager.h" -#include "maplayer.h" -#include "party.h" - -#include "being/localplayer.h" -#include "being/playerrelations.h" - -#include "input/keyboardconfig.h" - -#include "gui/confirmdialog.h" -#include "gui/okdialog.h" -#include "gui/outfitwindow.h" -#include "gui/setup.h" -#include "gui/textdialog.h" -#include "gui/whoisonline.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/browserbox.h" -#include "gui/widgets/chattab.h" -#include "gui/widgets/label.h" -#include "gui/widgets/popup.h" -#include "gui/widgets/scrollarea.h" - -#include "net/net.h" -#include "net/guildhandler.h" -#include "net/partyhandler.h" - -#include "utils/gettext.h" - -#include "debug.h" - -extern unsigned int tmwServerVersion; - -namespace -{ - static class SortFriendsFunctor final - { - public: - bool operator() (const Avatar *const m1, - const Avatar *const m2) const - { - if (!m1 || !m2) - return false; - - if (m1->getOnline() != m2->getOnline()) - return m1->getOnline() > m2->getOnline(); - - if (m1->getName() != m2->getName()) - { - std::string s1 = m1->getName(); - std::string s2 = m2->getName(); - toLower(s1); - toLower(s2); - return s1 < s2; - } - return false; - } - } friendSorter; -} // namespace - -class SocialTab : public Tab -{ -public: - A_DELETE_COPY(SocialTab) - - virtual void invite() - { - } - - virtual void leave() - { - } - - virtual void updateList() - { - } - - virtual void updateAvatar(const std::string &name A_UNUSED) - { - } - - virtual void resetDamage(const std::string &name A_UNUSED) - { - } - - virtual void selectIndex(const unsigned num A_UNUSED) - { } - -protected: - friend class SocialWindow; - - explicit SocialTab(const Widget2 *const widget): - Tab(widget), - mInviteDialog(nullptr), - mConfirmDialog(nullptr), - mScroll(nullptr), - mList(nullptr), - mCounterString() - { - } - - virtual ~SocialTab() - { - // Cleanup dialogs - if (mInviteDialog) - { - mInviteDialog->close(); - mInviteDialog->scheduleDelete(); - mInviteDialog = nullptr; - } - - if (mConfirmDialog) - { - mConfirmDialog->close(); - mConfirmDialog->scheduleDelete(); - mConfirmDialog = nullptr; - } - } - - void setCurrent() override - { - updateCounter(); - } - - void updateCounter() const - { - if (socialWindow) - socialWindow->setCounter(this, mCounterString); - } - - virtual void buildCounter(const int online A_UNUSED = 0, - const int total A_UNUSED = 0) - { - } - - TextDialog *mInviteDialog; - ConfirmDialog *mConfirmDialog; - ScrollArea *mScroll; - AvatarListBox *mList; - std::string mCounterString; -}; - -class SocialGuildTab final : public SocialTab, public gcn::ActionListener -{ -public: - SocialGuildTab(const Widget2 *const widget, - Guild *const guild, const bool showBackground) : - SocialTab(widget), - gcn::ActionListener(), - mGuild(guild) - { - // TRANSLATORS: tab in social window - setCaption(_("Guild")); - - setTabColor(&getThemeColor(Theme::GUILD_SOCIAL_TAB), - &getThemeColor(Theme::GUILD_SOCIAL_TAB_OUTLINE)); - setHighlightedTabColor(&getThemeColor( - Theme::GUILD_SOCIAL_TAB_HIGHLIGHTED), &getThemeColor( - Theme::GUILD_SOCIAL_TAB_HIGHLIGHTED_OUTLINE)); - setSelectedTabColor(&getThemeColor(Theme::GUILD_SOCIAL_TAB_SELECTED), - &getThemeColor(Theme::GUILD_SOCIAL_TAB_SELECTED_OUTLINE)); - - mList = new AvatarListBox(this, guild); - mScroll = new ScrollArea(mList, showBackground, - "social_background.xml"); - - mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); - mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); - } - - A_DELETE_COPY(SocialGuildTab) - - ~SocialGuildTab() - { - delete mList; - mList = nullptr; - delete mScroll; - mScroll = nullptr; - } - - void action(const gcn::ActionEvent &event) override - { - const std::string &eventId = event.getId(); - if (eventId == "do invite") - { - const std::string name = mInviteDialog->getText(); - Net::getGuildHandler()->invite(mGuild->getId(), name); - - if (localChatTab) - { - localChatTab->chatLog(strprintf( - // TRANSLATORS: chat message - _("Invited user %s to guild %s."), - name.c_str(), mGuild->getName().c_str()), BY_SERVER); - } - mInviteDialog = nullptr; - } - else if (eventId == "~do invite") - { - mInviteDialog = nullptr; - } - else if (eventId == "yes") - { - Net::getGuildHandler()->leave(mGuild->getId()); - if (localChatTab) - { - // TRANSLATORS: chat message - localChatTab->chatLog(strprintf(_("Guild %s quit requested."), - mGuild->getName().c_str()), BY_SERVER); - } - mConfirmDialog = nullptr; - } - else if (eventId == "~yes") - { - mConfirmDialog = nullptr; - } - } - - void invite() override - { - // TRANSLATORS: guild invite message - mInviteDialog = new TextDialog(_("Member Invite to Guild"), - // TRANSLATORS: guild invite message - strprintf(_("Who would you like to invite to guild %s?"), - mGuild->getName().c_str()), socialWindow); - mInviteDialog->setActionEventId("do invite"); - mInviteDialog->addActionListener(this); - } - - void leave() override - { - // TRANSLATORS: guild leave message - mConfirmDialog = new ConfirmDialog(_("Leave Guild?"), - // TRANSLATORS: guild leave message - strprintf(_("Are you sure you want to leave guild %s?"), - mGuild->getName().c_str()), SOUND_REQUEST, socialWindow); - - mConfirmDialog->addActionListener(this); - } - - void buildCounter(const int online0, const int total0) - { - if (online0 || total0) - { - // TRANSLATORS: social window label - mCounterString = strprintf(_("Members: %u/%u"), online0, total0); - } - else - { - if (!player_node) - return; - - const Guild *const guild = player_node->getGuild(); - if (!guild) - return; - - const Guild::MemberList *const members = guild->getMembers(); - int online = 0; - int total = 0; - FOR_EACHP (Guild::MemberList::const_iterator, it, members) - { - if ((*it)->getOnline()) - online ++; - total ++; - } - - // TRANSLATORS: social window label - mCounterString = strprintf(_("Players: %u/%u"), online, total); - } - updateCounter(); - } - -private: - Guild *mGuild; -}; - -class SocialGuildTab2 final : public SocialTab, public gcn::ActionListener -{ -public: - SocialGuildTab2(const Widget2 *const widget, Guild *const guild, - const bool showBackground) : - SocialTab(widget), - gcn::ActionListener() - { - // TRANSLATORS: tab in social window - setCaption(_("Guild")); - - setTabColor(&getThemeColor(Theme::GUILD_SOCIAL_TAB), - &getThemeColor(Theme::GUILD_SOCIAL_TAB_OUTLINE)); - setHighlightedTabColor(&getThemeColor( - Theme::GUILD_SOCIAL_TAB_HIGHLIGHTED), &getThemeColor( - Theme::GUILD_SOCIAL_TAB_HIGHLIGHTED_OUTLINE)); - setSelectedTabColor(&getThemeColor(Theme::GUILD_SOCIAL_TAB_SELECTED), - &getThemeColor(Theme::GUILD_SOCIAL_TAB_SELECTED_OUTLINE)); - - mList = new AvatarListBox(this, guild); - mScroll = new ScrollArea(mList, showBackground, - "social_background.xml"); - - mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); - mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); - } - - A_DELETE_COPY(SocialGuildTab2) - - ~SocialGuildTab2() - { - delete mList; - mList = nullptr; - delete mScroll; - mScroll = nullptr; - } - - void action(const gcn::ActionEvent &event A_UNUSED) override - { - } - - void buildCounter(const int online0 A_UNUSED, const int total0 A_UNUSED) - { - if (!player_node) - return; - - const Guild *const guild = player_node->getGuild(); - if (!guild) - return; - - const Guild::MemberList *const members = guild->getMembers(); - int online = 0; - int total = 0; - FOR_EACHP (Guild::MemberList::const_iterator, it, members) - { - if ((*it)->getOnline()) - online ++; - total ++; - } - - // TRANSLATORS: social window label - mCounterString = strprintf(_("Players: %u/%u"), online, total); - updateCounter(); - } -}; - -class SocialPartyTab final : public SocialTab, public gcn::ActionListener -{ -public: - SocialPartyTab(const Widget2 *const widget, - Party *const party, const bool showBackground) : - SocialTab(widget), - gcn::ActionListener(), - mParty(party) - { - // TRANSLATORS: tab in social window - setCaption(_("Party")); - - setTabColor(&getThemeColor(Theme::PARTY_SOCIAL_TAB), - &getThemeColor(Theme::PARTY_SOCIAL_TAB_OUTLINE)); - setHighlightedTabColor(&getThemeColor( - Theme::PARTY_SOCIAL_TAB_HIGHLIGHTED), &getThemeColor( - Theme::PARTY_SOCIAL_TAB_HIGHLIGHTED_OUTLINE)); - setSelectedTabColor(&getThemeColor(Theme::PARTY_SOCIAL_TAB_SELECTED), - &getThemeColor(Theme::PARTY_SOCIAL_TAB_SELECTED_OUTLINE)); - - mList = new AvatarListBox(this, party); - mScroll = new ScrollArea(mList, showBackground, - "social_background.xml"); - - mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); - mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); - } - - A_DELETE_COPY(SocialPartyTab) - - ~SocialPartyTab() - { - delete mList; - mList = nullptr; - delete mScroll; - mScroll = nullptr; - } - - void action(const gcn::ActionEvent &event) override - { - const std::string &eventId = event.getId(); - if (eventId == "do invite") - { - const std::string name = mInviteDialog->getText(); - Net::getPartyHandler()->invite(name); - - if (localChatTab) - { - // TRANSLATORS: chat message - localChatTab->chatLog(strprintf(_("Invited user %s to party."), - name.c_str()), BY_SERVER); - } - mInviteDialog = nullptr; - } - else if (eventId == "~do invite") - { - mInviteDialog = nullptr; - } - else if (eventId == "yes") - { - Net::getPartyHandler()->leave(); - if (localChatTab) - { - // TRANSLATORS: tab in social window - localChatTab->chatLog(strprintf(_("Party %s quit requested."), - mParty->getName().c_str()), BY_SERVER); - } - mConfirmDialog = nullptr; - } - else if (eventId == "~yes") - { - mConfirmDialog = nullptr; - } - } - - void invite() override - { - // TRANSLATORS: party invite message - mInviteDialog = new TextDialog(_("Member Invite to Party"), - // TRANSLATORS: party invite message - strprintf(_("Who would you like to invite to party %s?"), - mParty->getName().c_str()), socialWindow); - mInviteDialog->setActionEventId("do invite"); - mInviteDialog->addActionListener(this); - } - - void leave() override - { - // TRANSLATORS: party leave message - mConfirmDialog = new ConfirmDialog(_("Leave Party?"), - // TRANSLATORS: party leave message - strprintf(_("Are you sure you want to leave party %s?"), - mParty->getName().c_str()), SOUND_REQUEST, socialWindow); - - mConfirmDialog->addActionListener(this); - } - - void buildCounter(const int online0 A_UNUSED, const int total0 A_UNUSED) - { - if (!player_node) - return; - - const Party *const party = player_node->getParty(); - if (!party) - return; - - const Party::MemberList *const members = party->getMembers(); - int online = 0; - int total = 0; - FOR_EACHP (Party::MemberList::const_iterator, it, members) - { - if ((*it)->getOnline()) - online ++; - total ++; - } - - // TRANSLATORS: social window label - mCounterString = strprintf(_("Players: %u/%u"), online, total); - updateCounter(); - } - -private: - Party *mParty; -}; - -class BeingsListModal final : public AvatarListModel -{ -public: - BeingsListModal() : - AvatarListModel(), - mMembers() - { - } - - A_DELETE_COPY(BeingsListModal) - - ~BeingsListModal() - { - delete_all(mMembers); - mMembers.clear(); - } - - std::vector *getMembers() - { - return &mMembers; - } - - Avatar *getAvatarAt(int index) override - { - return mMembers[index]; - } - - int getNumberOfElements() override - { - return static_cast(mMembers.size()); - } - - std::vector mMembers; -}; - -class SocialPlayersTab final : public SocialTab -{ -public: - SocialPlayersTab(const Widget2 *const widget, - std::string name, const bool showBackground) : - SocialTab(widget), - mBeings(new BeingsListModal) - { - mList = new AvatarListBox(this, mBeings); - mScroll = new ScrollArea(mList, showBackground, - "social_background.xml"); - - mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); - mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); - - updateList(); - setCaption(name); - } - - A_DELETE_COPY(SocialPlayersTab) - - ~SocialPlayersTab() - { - delete mList; - mList = nullptr; - delete mScroll; - mScroll = nullptr; - delete mBeings; - mBeings = nullptr; - } - - void updateList() override - { - getPlayersAvatars(); - } - - void updateAvatar(const std::string &name) override - { - if (!actorSpriteManager) - return; - - Avatar *const avatar = findAvatarbyName(name); - if (!avatar) - return; - if (Party::getParty(1)) - { - const PartyMember *const pm = Party::getParty(1)->getMember(name); - if (pm && pm->getMaxHp() > 0) - { - avatar->setMaxHp(pm->getMaxHp()); - avatar->setHp(pm->getHp()); - } - } - const Being *const being = actorSpriteManager->findBeingByName( - name, Being::PLAYER); - if (being) - { - avatar->setDamageHp(being->getDamageTaken()); - avatar->setLevel(being->getLevel()); - avatar->setGender(being->getGender()); - avatar->setIp(being->getIp()); - } - } - - void resetDamage(const std::string &name) override - { - if (!actorSpriteManager) - return; - - Avatar *const avatar = findAvatarbyName(name); - if (!avatar) - return; - avatar->setDamageHp(0); - Being *const being = actorSpriteManager->findBeingByName( - name, Being::PLAYER); - - if (being) - being->setDamageTaken(0); - } - - Avatar* findAvatarbyName(std::string name) - { - std::vector *const avatars = mBeings->getMembers(); - if (!avatars) - return nullptr; - - Avatar *ava = nullptr; - std::vector::const_iterator i = avatars->begin(); - const std::vector::const_iterator i_end = avatars->end(); - while (i != i_end) - { - ava = (*i); - if (ava && ava->getName() == name) - return ava; - ++i; - } - ava = new Avatar(name); - ava->setOnline(true); - avatars->push_back(ava); - return ava; - } - - void getPlayersAvatars() - { - std::vector *const avatars = mBeings->getMembers(); - if (!avatars) - return; - - if (actorSpriteManager) - { - StringVect names; - actorSpriteManager->getPlayerNames(names, false); - - std::vector::iterator ai = avatars->begin(); - while (ai != avatars->end()) - { - bool finded = false; - const Avatar *const ava = (*ai); - if (!ava) - break; - - StringVectCIter i = names.begin(); - const StringVectCIter i_end = names.end(); - while (i != i_end) - { - if (ava->getName() == (*i) && (*i) != "") - { - finded = true; - break; - } - ++i; - } - - if (!finded) - { - delete *ai; - ai = avatars->erase(ai); - } - else - { - ++ai; - } - } - - StringVectCIter i = names.begin(); - const StringVectCIter i_end = names.end(); - - while (i != i_end) - { - if ((*i) != "") - updateAvatar(*i); - ++i; - } - } - // TRANSLATORS: social window label - mCounterString = strprintf(_("Visible players: %d"), - static_cast(avatars->size())); - updateCounter(); - } - -private: - BeingsListModal *mBeings; -}; - - -class SocialNavigationTab final : public SocialTab -{ -public: - SocialNavigationTab(const Widget2 *const widget, - const bool showBackground) : - SocialTab(widget), - mBeings(new BeingsListModal) - { - mList = new AvatarListBox(this, mBeings); - mScroll = new ScrollArea(mList, showBackground, - "social_background.xml"); - - mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); - mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); - - // TRANSLATORS: Navigation tab name in social window. Should be small - setCaption(_("Nav")); - } - - A_DELETE_COPY(SocialNavigationTab) - - ~SocialNavigationTab() - { - delete mList; - mList = nullptr; - delete mScroll; - mScroll = nullptr; - delete mBeings; - mBeings = nullptr; - } - - void updateList() override - { - if (!socialWindow || !player_node) - return; - - const Map *const map = socialWindow->getMap(); - if (!map || map->empty()) - return; - - if (socialWindow->getProcessedPortals()) - return; - - std::vector *const avatars = mBeings->getMembers(); - std::vector portals = map->getPortals(); - - std::vector::const_iterator i = portals.begin(); - const SpecialLayer *const specialLayer = map->getSpecialLayer(); - - std::vector::iterator ia = avatars->begin(); - - while (ia != avatars->end()) - { - delete *ia; - ++ ia; - } - - avatars->clear(); - - int online = 0; - int total = 0; - - int idx = 0; - while (i != portals.end()) - { - MapItem *portal = *i; - if (!portal) - continue; - - const int x = portal->getX(); - const int y = portal->getY(); - - const std::string name = strprintf("%s [%d %d]", - portal->getComment().c_str(), x, y); - - Avatar *const ava = new Avatar(name); - if (player_node) - ava->setOnline(player_node->isReachable(x, y, true)); - else - ava->setOnline(false); - ava->setLevel(-1); - ava->setType(portal->getType()); - ava->setX(x); - ava->setY(y); - avatars->push_back(ava); - - if (ava->getOnline()) - online ++; - total ++; - - if (config.getBoolValue("drawHotKeys") && idx < 80 && outfitWindow) - { - Being *const being = actorSpriteManager - ->findPortalByTile(x, y); - if (being) - { - being->setName(keyboard.getKeyShortString( - outfitWindow->keyName(idx))); - } - - if (specialLayer) - { - portal = specialLayer->getTile(ava->getX(), ava->getY()); - if (portal) - { - portal->setName(keyboard.getKeyShortString( - outfitWindow->keyName(idx))); - } - } - } - - ++i; - idx ++; - } - if (socialWindow) - socialWindow->setProcessedPortals(true); - - // TRANSLATORS: social window label - mCounterString = strprintf(_("Portals: %u/%u"), online, total); - updateCounter(); - } - - - void selectIndex(const unsigned num) override - { - if (!player_node) - return; - - std::vector *const avatars = mBeings->getMembers(); - if (!avatars || avatars->size() <= num) - return; - - const Avatar *const ava = avatars->at(num); - if (ava && player_node) - player_node->navigateTo(ava->getX(), ava->getY()); - } - - void updateNames() - { - if (!socialWindow) - return; - - std::vector *const avatars = mBeings->getMembers(); - if (!avatars) - return; - - const Map *const map = socialWindow->getMap(); - if (!map) - return; - - std::vector::const_iterator i = avatars->begin(); - const std::vector::const_iterator i_end = avatars->end(); - while (i != i_end) - { - Avatar *const ava = *i; - if (!ava) - break; - - const MapItem *const item = map->findPortalXY( - ava->getX(), ava->getY()); - if (item) - { - const std::string name = strprintf("%s [%d %d]", - item->getComment().c_str(), item->getX(), item->getY()); - ava->setName(name); - ava->setOriginalName(name); - } - - ++i; - } - } - - int getPortalIndex(const int x, const int y) - { - if (!socialWindow) - return -1; - - std::vector *const avatars = mBeings->getMembers(); - if (!avatars) - return -1; - - const Map *const map = socialWindow->getMap(); - if (!map) - return 01; - - std::vector::const_iterator i = avatars->begin(); - const std::vector::const_iterator i_end = avatars->end(); - unsigned num = 0; - while (i != i_end) - { - const Avatar *const ava = *i; - if (!ava) - break; - - if (ava->getX() == x && ava->getY() == y) - return num; - - ++i; - num ++; - } - return -1; - } - - void addPortal(const int x, const int y) - { - if (!socialWindow || !player_node) - return; - - const Map *const map = socialWindow->getMap(); - if (!map) - return; - - std::vector *const avatars = mBeings->getMembers(); - - if (!avatars) - return; - - const MapItem *const portal = map->findPortalXY(x, y); - if (!portal) - return; - - const std::string name = strprintf("%s [%d %d]", - portal->getComment().c_str(), x, y); - - Avatar *const ava = new Avatar(name); - if (player_node) - ava->setOnline(player_node->isReachable(x, y, true)); - else - ava->setOnline(false); - ava->setLevel(-1); - ava->setType(portal->getType()); - ava->setX(x); - ava->setY(y); - avatars->push_back(ava); - } - - void removePortal(const int x, const int y) - { - if (!socialWindow || !player_node) - return; - - const Map *const map = socialWindow->getMap(); - if (!map) - return; - - std::vector *const avatars = mBeings->getMembers(); - - if (!avatars) - return; - - std::vector::iterator i = avatars->begin(); - const std::vector::iterator i_end = avatars->end(); - - while (i != i_end) - { - Avatar *ava = (*i); - - if (!ava) - break; - - if (ava->getX() == x && ava->getY() == y) - { - delete ava; - avatars->erase(i); - return; - } - - ++ i; - } - } - -private: - BeingsListModal *mBeings; -}; - - -#define addAvatars(mob, str, type) \ -{\ - ava = new Avatar(str);\ - ava->setOnline(false);\ - ava->setLevel(-1);\ - ava->setType(MapItem::SEPARATOR);\ - ava->setX(0);\ - ava->setY(0);\ - avatars->push_back(ava);\ - mobs = actorSpriteManager->get##mob##s();\ - i = mobs.begin();\ - i_end = mobs.end();\ - while (i != i_end)\ - {\ - std::string name;\ - int level = -1;\ - if (*i == "")\ - {\ - name = _("(default)");\ - level = 0;\ - }\ - else\ - {\ - name = *i;\ - }\ - ava = new Avatar(name);\ - ava->setOnline(true);\ - ava->setLevel(level);\ - ava->setType(MapItem::type);\ - ava->setX(0);\ - ava->setY(0);\ - avatars->push_back(ava);\ - ++ i;\ - }\ -} - -#define updateAtkListStart() \ - if (!socialWindow || !player_node || !actorSpriteManager)\ - return;\ - std::vector *const avatars = mBeings->getMembers();\ - std::vector::iterator ia = avatars->begin();\ - while (ia != avatars->end())\ - {\ - delete *ia;\ - ++ ia;\ - }\ - avatars->clear();\ - Avatar *ava;\ - std::list mobs;\ - std::list::const_iterator i;\ - std::list::const_iterator i_end; - -class SocialAttackTab final : public SocialTab -{ -public: - SocialAttackTab(const Widget2 *const widget, - const bool showBackground) : - SocialTab(widget), - mBeings(new BeingsListModal) - { - mList = new AvatarListBox(this, mBeings); - mScroll = new ScrollArea(mList, showBackground, - "social_background.xml"); - - mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); - mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); - - // TRANSLATORS: Attack filter tab name in social window. Should be small - setCaption(_("Atk")); - } - - A_DELETE_COPY(SocialAttackTab) - - ~SocialAttackTab() - { - delete mList; - mList = nullptr; - delete mScroll; - mScroll = nullptr; - delete mBeings; - mBeings = nullptr; - } - - void updateList() override - { - updateAtkListStart(); - // TRANSLATORS: mobs group name in social window - addAvatars(PriorityAttackMob, _("Priority mobs"), PRIORITY); - // TRANSLATORS: mobs group name in social window - addAvatars(AttackMob, _("Attack mobs"), ATTACK); - // TRANSLATORS: mobs group name in social window - addAvatars(IgnoreAttackMob, _("Ignore mobs"), IGNORE_); - } - -private: - BeingsListModal *mBeings; -}; - -class SocialPickupTab final : public SocialTab -{ -public: - SocialPickupTab(const Widget2 *const widget, - const bool showBackground) : - SocialTab(widget), - mBeings(new BeingsListModal) - { - mList = new AvatarListBox(this, mBeings); - mScroll = new ScrollArea(mList, showBackground, - "social_background.xml"); - - mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); - mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); - - // TRANSLATORS: Pickup filter tab name in social window. Should be small - setCaption(_("Pik")); - } - - A_DELETE_COPY(SocialPickupTab) - - ~SocialPickupTab() - { - delete mList; - mList = nullptr; - delete mScroll; - mScroll = nullptr; - delete mBeings; - mBeings = nullptr; - } - - void updateList() override - { - updateAtkListStart(); - // TRANSLATORS: items group name in social window - addAvatars(PickupItem, _("Pickup items"), PICKUP); - // TRANSLATORS: items group name in social window - addAvatars(IgnorePickupItem, _("Ignore items"), NOPICKUP); - } - -private: - BeingsListModal *mBeings; -}; - - -class SocialFriendsTab final : public SocialTab -{ -public: - SocialFriendsTab(const Widget2 *const widget, - std::string name, const bool showBackground) : - SocialTab(widget), - mBeings(new BeingsListModal) - { - mList = new AvatarListBox(this, mBeings); - mScroll = new ScrollArea(mList, showBackground, - "social_background.xml"); - - mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); - mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); - - updateList(); - setCaption(name); - } - - A_DELETE_COPY(SocialFriendsTab) - - ~SocialFriendsTab() - { - delete mList; - mList = nullptr; - delete mScroll; - mScroll = nullptr; - delete mBeings; - mBeings = nullptr; - } - - void updateList() override - { - getPlayersAvatars(); - } - - void getPlayersAvatars() - { - if (!actorSpriteManager) - return; - - std::vector *const avatars = mBeings->getMembers(); - if (!avatars) - return; - - std::vector::iterator ia = avatars->begin(); - while (ia != avatars->end()) - { - delete *ia; - ++ ia; - } - avatars->clear(); - - const StringVect *const players - = player_relations.getPlayersByRelation(PlayerRelation::FRIEND); - - const std::set &players2 = whoIsOnline->getOnlineNicks(); - - if (!players) - return; - - int online = 0; - int total = 0; - - FOR_EACHP (StringVectCIter, it, players) - { - Avatar *const ava = new Avatar(*it); - if (actorSpriteManager->findBeingByName(*it, Being::PLAYER) - || players2.find(*it) != players2.end()) - { - ava->setOnline(true); - online ++; - } - total ++; - avatars->push_back(ava); - } - std::sort(avatars->begin(), avatars->end(), friendSorter); - delete players; - - // TRANSLATORS: social window label - mCounterString = strprintf(_("Friends: %u/%u"), online, total); - updateCounter(); - } - -private: - BeingsListModal *mBeings; -}; - - -class CreatePopup final : public Popup, public LinkHandler -{ -public: - CreatePopup() : - Popup("SocialCreatePopup"), - LinkHandler(), - mBrowserBox(new BrowserBox(this)) - { - mBrowserBox->setPosition(4, 4); - mBrowserBox->setHighlightMode(BrowserBox::BACKGROUND); - mBrowserBox->setOpaque(false); - mBrowserBox->setLinkHandler(this); - - // TRANSLATORS: party popup item - mBrowserBox->addRow(strprintf("@@party|%s@@", _("Create Party"))); - mBrowserBox->addRow("##3---"); - // TRANSLATORS: party popup item - mBrowserBox->addRow(strprintf("@@cancel|%s@@", _("Cancel"))); - - add(mBrowserBox); - - setContentSize(mBrowserBox->getWidth() + 8, - mBrowserBox->getHeight() + 8); - } - - A_DELETE_COPY(CreatePopup) - - void handleLink(const std::string &link, - gcn::MouseEvent *event A_UNUSED) override - { - if (link == "guild" && socialWindow) - { - socialWindow->showGuildCreate(); - } - else if (link == "party" && socialWindow) - { - socialWindow->showPartyCreate(); - } - - setVisible(false); - } - - void show(gcn::Widget *parent) - { - if (!parent) - return; - - int x, y; - parent->getAbsolutePosition(x, y); - y += parent->getHeight(); - setPosition(x, y); - setVisible(true); - requestMoveToTop(); - } - -private: - BrowserBox* mBrowserBox; -}; - -SocialWindow::SocialWindow() : - // TRANSLATORS: social window name - Window(_("Social"), false, nullptr, "social.xml"), - gcn::ActionListener(), - mGuildInvited(0), - mGuildAcceptDialog(nullptr), - mGuildCreateDialog(nullptr), - mPartyInviter(), - mPartyAcceptDialog(nullptr), - mPartyCreateDialog(nullptr), - mGuilds(), - mParties(), - mAttackFilter(nullptr), - mPickupFilter(nullptr), - // TRANSLATORS: here P is title for visible players tab in social window - mPlayers(new SocialPlayersTab(this, _("P"), - getOptionBool("showtabbackground"))), - mNavigation(new SocialNavigationTab(this, - getOptionBool("showtabbackground"))), - // TRANSLATORS: here F is title for friends tab in social window - mFriends(new SocialFriendsTab(this, _("F"), - getOptionBool("showtabbackground"))), - mCreatePopup(new CreatePopup), - // TRANSLATORS: social window button - mCreateButton(new Button(this, _("Create"), "create", this)), - // TRANSLATORS: social window button - mInviteButton(new Button(this, _("Invite"), "invite", this)), - // TRANSLATORS: social window button - mLeaveButton(new Button(this, _("Leave"), "leave", this)), - mCountLabel(new Label(this, "1000 / 1000")), - mTabs(new TabbedArea(this)), - mMap(nullptr), - mLastUpdateTime(0), - mNeedUpdate(false), - mProcessedPortals(false) -{ - setWindowName("Social"); - setVisible(false); - setSaveVisible(true); - setResizable(true); - setSaveVisible(true); - setCloseButton(true); - setStickyButtonLock(true); - - setMinWidth(120); - setMinHeight(55); - setDefaultSize(590, 200, 180, 300); - if (setupWindow) - setupWindow->registerWindowForReset(this); - - place(0, 0, mCreateButton); - place(1, 0, mInviteButton); - place(2, 0, mLeaveButton); - place(0, 1, mCountLabel); - place(0, 2, mTabs, 4, 4); - - widgetResized(gcn::Event(nullptr)); - - loadWindowState(); - - mTabs->addTab(mPlayers, mPlayers->mScroll); - mTabs->addTab(mFriends, mFriends->mScroll); - mTabs->addTab(mNavigation, mNavigation->mScroll); - - if (config.getBoolValue("enableAttackFilter")) - { - mAttackFilter = new SocialAttackTab(this, - getOptionBool("showtabbackground")); - mTabs->addTab(mAttackFilter, mAttackFilter->mScroll); - } - else - { - mAttackFilter = nullptr; - } - - if (config.getBoolValue("enablePickupFilter")) - { - mPickupFilter = new SocialPickupTab(this, - getOptionBool("showtabbackground")); - mTabs->addTab(mPickupFilter, mPickupFilter->mScroll); - } - else - { - mPickupFilter = nullptr; - } - - if (player_node && player_node->getParty()) - addTab(player_node->getParty()); - - if (player_node && player_node->getGuild()) - addTab(player_node->getGuild()); - - enableVisibleSound(true); - updateButtons(); -} - -SocialWindow::~SocialWindow() -{ - if (mGuildAcceptDialog) - { - mGuildAcceptDialog->close(); - mGuildAcceptDialog->scheduleDelete(); - mGuildAcceptDialog = nullptr; - - mGuildInvited = 0; - } - - if (mPartyAcceptDialog) - { - mPartyAcceptDialog->close(); - mPartyAcceptDialog->scheduleDelete(); - mPartyAcceptDialog = nullptr; - - mPartyInviter.clear(); - } - delete mCreatePopup; - mCreatePopup = nullptr; - delete mPlayers; - mPlayers = nullptr; - delete mNavigation; - mNavigation = nullptr; - delete mAttackFilter; - mAttackFilter = nullptr; - delete mPickupFilter; - mPickupFilter = nullptr; - delete mFriends; - mFriends = nullptr; -} - -bool SocialWindow::addTab(Guild *const guild) -{ - if (mGuilds.find(guild) != mGuilds.end()) - return false; - - SocialTab *tab = nullptr; - if (guild->getServerGuild()) - { - tab = new SocialGuildTab(this, guild, - getOptionBool("showtabbackground")); - } - else - { - tab = new SocialGuildTab2(this, guild, - getOptionBool("showtabbackground")); - } - - mGuilds[guild] = tab; - mTabs->addTab(tab, tab->mScroll); - - updateButtons(); - - return true; -} - -bool SocialWindow::removeTab(Guild *const guild) -{ - const GuildMap::iterator it = mGuilds.find(guild); - if (it == mGuilds.end()) - return false; - - mTabs->removeTab(it->second); - delete it->second; - mGuilds.erase(it); - - updateButtons(); - - return true; -} - -bool SocialWindow::addTab(Party *const party) -{ - if (mParties.find(party) != mParties.end()) - return false; - - SocialPartyTab *const tab = new SocialPartyTab(this, party, - getOptionBool("showtabbackground")); - mParties[party] = tab; - - mTabs->addTab(tab, tab->mScroll); - - updateButtons(); - - return true; -} - -bool SocialWindow::removeTab(Party *const party) -{ - const PartyMap::iterator it = mParties.find(party); - if (it == mParties.end()) - return false; - - mTabs->removeTab(it->second); - delete it->second; - mParties.erase(it); - - updateButtons(); - - return true; -} - -void SocialWindow::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - - if (event.getSource() == mPartyAcceptDialog) - { - if (eventId == "yes") - { - if (localChatTab) - { - localChatTab->chatLog( - // TRANSLATORS: chat message - strprintf(_("Accepted party invite from %s."), - mPartyInviter.c_str())); - } - Net::getPartyHandler()->inviteResponse(mPartyInviter, true); - } - else if (eventId == "no") - { - if (localChatTab) - { - localChatTab->chatLog( - // TRANSLATORS: chat message - strprintf(_("Rejected party invite from %s."), - mPartyInviter.c_str())); - } - Net::getPartyHandler()->inviteResponse(mPartyInviter, false); - } - - mPartyInviter.clear(); - mPartyAcceptDialog = nullptr; - } - else if (event.getSource() == mGuildAcceptDialog) - { - if (eventId == "yes") - { - if (localChatTab) - { - localChatTab->chatLog( - // TRANSLATORS: chat message - strprintf(_("Accepted guild invite from %s."), - mPartyInviter.c_str())); - } - if (!guildManager || !GuildManager::getEnableGuildBot()) - Net::getGuildHandler()->inviteResponse(mGuildInvited, true); - else - guildManager->inviteResponse(true); - } - else if (eventId == "no") - { - if (localChatTab) - { - localChatTab->chatLog( - // TRANSLATORS: chat message - strprintf(_("Rejected guild invite from %s."), - mPartyInviter.c_str())); - } - if (!guildManager || !GuildManager::getEnableGuildBot()) - Net::getGuildHandler()->inviteResponse(mGuildInvited, false); - else - guildManager->inviteResponse(false); - } - - mGuildInvited = 0; - mGuildAcceptDialog = nullptr; - } - else if (eventId == "create") - { - showPartyCreate(); - } - else if (eventId == "invite" && mTabs->getSelectedTabIndex() > -1) - { - if (mTabs->getSelectedTab()) - static_cast(mTabs->getSelectedTab())->invite(); - } - else if (eventId == "leave" && mTabs->getSelectedTabIndex() > -1) - { - if (mTabs->getSelectedTab()) - static_cast(mTabs->getSelectedTab())->leave(); - } - else if (eventId == "create guild") - { - if (tmwServerVersion > 0) - return; - - std::string name = mGuildCreateDialog->getText(); - - if (name.size() > 16) - return; - - Net::getGuildHandler()->create(name); - if (localChatTab) - { - // TRANSLATORS: chat message - localChatTab->chatLog(strprintf(_("Creating guild called %s."), - name.c_str()), BY_SERVER); - } - - mGuildCreateDialog = nullptr; - } - else if (eventId == "~create guild") - { - mGuildCreateDialog = nullptr; - } - else if (eventId == "create party") - { - std::string name = mPartyCreateDialog->getText(); - - if (name.size() > 16) - return; - - Net::getPartyHandler()->create(name); - if (localChatTab) - { - // TRANSLATORS: chat message - localChatTab->chatLog(strprintf(_("Creating party called %s."), - name.c_str()), BY_SERVER); - } - - mPartyCreateDialog = nullptr; - } - else if (eventId == "~create party") - { - mPartyCreateDialog = nullptr; - } -} - -void SocialWindow::showGuildCreate() -{ - // TRANSLATORS: guild creation message - mGuildCreateDialog = new TextDialog(_("Guild Name"), - // TRANSLATORS: guild creation message - _("Choose your guild's name."), this); - mGuildCreateDialog->setActionEventId("create guild"); - mGuildCreateDialog->addActionListener(this); -} - -void SocialWindow::showGuildInvite(const std::string &guildName, - const int guildId, - const std::string &inviterName) -{ - // check there isnt already an invite showing - if (mGuildInvited != 0) - { - if (localChatTab) - { - // TRANSLATORS: chat message - localChatTab->chatLog(_("Received guild request, but one already " - "exists."), BY_SERVER); - } - return; - } - - const std::string msg = strprintf( - // TRANSLATORS: chat message - _("%s has invited you to join the guild %s."), - inviterName.c_str(), guildName.c_str()); - - if (localChatTab) - localChatTab->chatLog(msg, BY_SERVER); - - // TRANSLATORS: guild invite message - mGuildAcceptDialog = new ConfirmDialog(_("Accept Guild Invite"), - msg, SOUND_REQUEST, false, false, this); - mGuildAcceptDialog->addActionListener(this); - mGuildInvited = guildId; -} - -void SocialWindow::showPartyInvite(const std::string &partyName, - const std::string &inviter) -{ - // check there isnt already an invite showing - if (!mPartyInviter.empty()) - { - if (localChatTab) - { - // TRANSLATORS: chat message - localChatTab->chatLog(_("Received party request, but one already " - "exists."), BY_SERVER); - } - return; - } - - std::string msg; - if (inviter.empty()) - { - if (partyName.empty()) - { - // TRANSLATORS: party invite message - msg = _("You have been invited you to join a party."); - } - else - { - // TRANSLATORS: party invite message - msg = strprintf(_("You have been invited to join the %s party."), - partyName.c_str()); - } - } - else - { - if (partyName.empty()) - { - // TRANSLATORS: party invite message - msg = strprintf(_("%s has invited you to join their party."), - inviter.c_str()); - } - else - { - // TRANSLATORS: party invite message - msg = strprintf(_("%s has invited you to join the %s party."), - inviter.c_str(), partyName.c_str()); - } - } - - if (localChatTab) - localChatTab->chatLog(msg, BY_SERVER); - - // show invite - // TRANSLATORS: party invite message - mPartyAcceptDialog = new ConfirmDialog(_("Accept Party Invite"), - msg, SOUND_REQUEST, false, false, this); - mPartyAcceptDialog->addActionListener(this); - mPartyInviter = inviter; -} - -void SocialWindow::showPartyCreate() -{ - if (!player_node) - return; - - if (player_node->getParty()) - { - // TRANSLATORS: party creation message - new OkDialog(_("Create Party"), - _("Cannot create party. You are already in a party"), - DIALOG_ERROR, true, true, this); - return; - } - - // TRANSLATORS: party creation message - mPartyCreateDialog = new TextDialog(_("Party Name"), - // TRANSLATORS: party creation message - _("Choose your party's name."), this); - mPartyCreateDialog->setActionEventId("create party"); - mPartyCreateDialog->addActionListener(this); -} - -void SocialWindow::updateActiveList() -{ - mNeedUpdate = true; -} - -void SocialWindow::slowLogic() -{ - BLOCK_START("SocialWindow::slowLogic") - const unsigned int nowTime = cur_time; - if (mNeedUpdate && nowTime - mLastUpdateTime > 1) - { - mPlayers->updateList(); - mFriends->updateList(); - mNeedUpdate = false; - mLastUpdateTime = nowTime; - } - else if (nowTime - mLastUpdateTime > 5) - { - mPlayers->updateList(); - mNeedUpdate = false; - mLastUpdateTime = nowTime; - } - BLOCK_END("SocialWindow::slowLogic") -} - -void SocialWindow::updateAvatar(const std::string &name) -{ - mPlayers->updateAvatar(name); -} - -void SocialWindow::resetDamage(const std::string &name) -{ - mPlayers->resetDamage(name); -} - -void SocialWindow::updateButtons() -{ - if (!mTabs) - return; - - const bool hasTabs = mTabs->getNumberOfTabs() > 0; - mInviteButton->setEnabled(hasTabs); - mLeaveButton->setEnabled(hasTabs); -} - -void SocialWindow::updatePortals() -{ - if (mNavigation) - mNavigation->updateList(); -} - -void SocialWindow::updatePortalNames() -{ - if (mNavigation) - static_cast(mNavigation)->updateNames(); -} - -void SocialWindow::selectPortal(const unsigned num) -{ - if (mNavigation) - mNavigation->selectIndex(num); -} - -int SocialWindow::getPortalIndex(const int x, const int y) -{ - if (mNavigation) - { - return static_cast( - mNavigation)->getPortalIndex(x, y); - } - else - { - return -1; - } -} - -void SocialWindow::addPortal(const int x, const int y) -{ - if (mNavigation) - static_cast(mNavigation)->addPortal(x, y); -} - -void SocialWindow::removePortal(const int x, const int y) -{ - if (mNavigation) - static_cast(mNavigation)->removePortal(x, y); -} - -void SocialWindow::nextTab() -{ - if (!mTabs) - return; - - int tab = mTabs->getSelectedTabIndex(); - - tab++; - if (tab == mTabs->getNumberOfTabs()) - tab = 0; - - mTabs->setSelectedTabByPos(tab); -} - -void SocialWindow::prevTab() -{ - if (!mTabs) - return; - - int tab = mTabs->getSelectedTabIndex(); - - if (tab == 0) - tab = mTabs->getNumberOfTabs(); - tab--; - - mTabs->setSelectedTabByPos(tab); -} - -void SocialWindow::updateAttackFilter() -{ - if (mAttackFilter) - mAttackFilter->updateList(); -} - -void SocialWindow::updatePickupFilter() -{ - if (mPickupFilter) - mPickupFilter->updateList(); -} - -void SocialWindow::updateParty() -{ - if (!player_node) - return; - - Party *const party = player_node->getParty(); - if (party) - { - PartyMap::iterator it = mParties.find(party); - if (it != mParties.end()) - { - SocialTab *const tab = (*it).second; - tab->buildCounter(); - } - } -} - -void SocialWindow::widgetResized(const gcn::Event &event) -{ - Window::widgetResized(event); - if (mTabs) - mTabs->adjustSize(); -} - -void SocialWindow::setCounter(const SocialTab *const tab, - const std::string &str) -{ - if (mTabs->getSelectedTab() == tab) - { - mCountLabel->setCaption(str); - mCountLabel->adjustSize(); - } -} - -void SocialWindow::updateGuildCounter(const int online, const int total) -{ - if (!player_node) - return; - - Guild *const guild = player_node->getGuild(); - if (guild) - { - GuildMap::iterator it = mGuilds.find(guild); - if (it != mGuilds.end()) - { - SocialTab *const tab = (*it).second; - tab->buildCounter(online, total); - } - } -} - -#ifdef USE_PROFILER -void SocialWindow::logicChildren() -{ - BLOCK_START("SocialWindow::logicChildren") - BasicContainer::logicChildren(); - BLOCK_END("SocialWindow::logicChildren") -} -#endif diff --git a/src/gui/socialwindow.h b/src/gui/socialwindow.h deleted file mode 100644 index 31d1b676a..000000000 --- a/src/gui/socialwindow.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_SOCIALWINDOW_H -#define GUI_SOCIALWINDOW_H - -#include "gui/widgets/window.h" - -#include - -#include -#include - -class Button; -class ConfirmDialog; -class CreatePopup; -class Guild; -class Label; -class Map; -class Party; -class SocialTab; -class TabbedArea; -class TextDialog; - -/** - * Party window. - * - * \ingroup Interface - */ -class SocialWindow final : public Window, private gcn::ActionListener -{ -public: - SocialWindow(); - - A_DELETE_COPY(SocialWindow) - - ~SocialWindow(); - - bool addTab(Guild *const guild); - - bool removeTab(Guild *const guild); - - bool addTab(Party *const party); - - bool removeTab(Party *const party); - - void action(const gcn::ActionEvent &event) override; - - void showGuildInvite(const std::string &guildName, const int guildId, - const std::string &inviterName); - - void showGuildCreate(); - - void showPartyInvite(const std::string &partyName, - const std::string &inviter = ""); - - void showPartyCreate(); - - void updateActiveList(); - - void updateAvatar(const std::string &name); - - void resetDamage(const std::string &name); - - void slowLogic(); - - void updatePortals(); - - void updatePortalNames(); - - void updateParty(); - - int getPortalIndex(const int x, const int y) A_WARN_UNUSED; - - void addPortal(const int x, const int y); - - void removePortal(const int x, const int y); - - void nextTab(); - - void prevTab(); - - const Map* getMap() const A_WARN_UNUSED - { return mMap; } - - void setMap(Map *const map) - { mMap = map; mProcessedPortals = false; } - - bool getProcessedPortals() const A_WARN_UNUSED - { return mProcessedPortals; } - - void setProcessedPortals(const bool n) - { mProcessedPortals = n; } - - void selectPortal(const unsigned num); - - void updateAttackFilter(); - - void updatePickupFilter(); - - void widgetResized(const gcn::Event &event) override; - - void setCounter(const SocialTab *const tab, const std::string &str); - - void updateGuildCounter(const int online = 0, const int total = 0); - -#ifdef USE_PROFILER - void logicChildren(); -#endif - -protected: - friend class SocialTab; - - void updateButtons(); - - int mGuildInvited; - ConfirmDialog *mGuildAcceptDialog; - TextDialog *mGuildCreateDialog; - - std::string mPartyInviter; - ConfirmDialog *mPartyAcceptDialog; - TextDialog *mPartyCreateDialog; - - typedef std::map GuildMap; - GuildMap mGuilds; - - typedef std::map PartyMap; - PartyMap mParties; - - SocialTab *mAttackFilter; - SocialTab *mPickupFilter; - SocialTab *mPlayers; - SocialTab *mNavigation; - SocialTab *mFriends; - - CreatePopup *mCreatePopup; - - Button *mCreateButton; - Button *mInviteButton; - Button *mLeaveButton; - Label *mCountLabel; - TabbedArea *mTabs; - Map *mMap; - - int mLastUpdateTime; - bool mNeedUpdate; - bool mProcessedPortals; -}; - -extern SocialWindow *socialWindow; - -#endif // GUI_SOCIALWINDOW_H diff --git a/src/gui/statuswindow.cpp b/src/gui/statuswindow.cpp deleted file mode 100644 index 767b4f537..000000000 --- a/src/gui/statuswindow.cpp +++ /dev/null @@ -1,886 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/statuswindow.h" - -#include "chatwindow.h" -#include "configuration.h" -#include "equipment.h" -#include "inventory.h" -#include "item.h" -#include "units.h" - -#include "being/localplayer.h" -#include "being/playerinfo.h" - -#include "gui/equipmentwindow.h" -#include "gui/setup.h" -#include "gui/viewport.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/label.h" -#include "gui/widgets/layouthelper.h" -#include "gui/widgets/progressbar.h" -#include "gui/widgets/scrollarea.h" -#include "gui/widgets/vertcontainer.h" - -#include "net/net.h" -#include "net/playerhandler.h" -#include "net/gamehandler.h" - -#include "utils/gettext.h" - -#include - -#include "debug.h" - -class AttrDisplay : public Container -{ - public: - enum Type - { - DERIVED = 0, - CHANGEABLE, - UNKNOWN - }; - - A_DELETE_COPY(AttrDisplay) - - virtual ~AttrDisplay(); - - virtual std::string update(); - - virtual Type getType() const - { return UNKNOWN; } - - std::string getValue() const - { - if (!mValue) - return "-"; - else - return mValue->getCaption(); - } - - const std::string &getShortName() const - { return mShortName; } - - protected: - AttrDisplay(const Widget2 *const widget, - const int id, const std::string &name, - const std::string &shortName); - - const int mId; - const std::string mName; - const std::string mShortName; - - LayoutHelper *mLayout; - Label *mLabel; - Label *mValue; -}; - -class DerDisplay final : public AttrDisplay -{ - public: - DerDisplay(const Widget2 *const widget, - const int id, const std::string &name, - const std::string &shortName); - - A_DELETE_COPY(DerDisplay) - - Type getType() const override - { return DERIVED; } -}; - -class ChangeDisplay final : public AttrDisplay, gcn::ActionListener -{ - public: - ChangeDisplay(const Widget2 *const widget, - const int id, const std::string &name, - const std::string &shortName); - - A_DELETE_COPY(ChangeDisplay) - - std::string update() override; - - Type getType() const override - { return CHANGEABLE; } - - void setPointsNeeded(int needed); - - void action(const gcn::ActionEvent &event) override; - - private: - int mNeeded; - - Label *mPoints; - Button *mDec; - Button *mInc; -}; - -StatusWindow::StatusWindow() : - Window(player_node ? player_node->getName() : - "?", false, nullptr, "status.xml"), - gcn::ActionListener(), - // TRANSLATORS: status window label - mLvlLabel(new Label(this, strprintf(_("Level: %d"), 0))), - // TRANSLATORS: status window label - mMoneyLabel(new Label(this, strprintf(_("Money: %s"), ""))), - // TRANSLATORS: status window label - mHpLabel(new Label(this, _("HP:"))), - mMpLabel(nullptr), - // TRANSLATORS: status window label - mXpLabel(new Label(this, _("Exp:"))), - mHpBar(nullptr), - mMpBar(nullptr), - mXpBar(nullptr), - mJobLvlLabel(nullptr), - mJobLabel(nullptr), - mJobBar(nullptr), - mAttrCont(new VertContainer(this, 32)), - mAttrScroll(new ScrollArea(mAttrCont, false)), - mDAttrCont(new VertContainer(this, 32)), - mDAttrScroll(new ScrollArea(mDAttrCont, false)), - mCharacterPointsLabel(new Label(this, "C")), - mCorrectionPointsLabel(nullptr), - // TRANSLATORS: status window button - mCopyButton(new Button(this, _("Copy to chat"), "copy", this)), - mAttrs() -{ - listen(CHANNEL_ATTRIBUTES); - - setWindowName("Status"); - if (setupWindow) - setupWindow->registerWindowForReset(this); - setResizable(true); - setCloseButton(true); - setSaveVisible(true); - setStickyButtonLock(true); - setDefaultSize((windowContainer->getWidth() - 480) / 2, - (windowContainer->getHeight() - 500) / 2, 480, 500); - - if (player_node && !player_node->getRaceName().empty()) - { - setCaption(strprintf("%s (%s)", player_node->getName().c_str(), - player_node->getRaceName().c_str())); - } - - int max = PlayerInfo::getAttribute(PlayerInfo::MAX_HP); - if (!max) - max = 1; - - mHpBar = new ProgressBar(this, static_cast(PlayerInfo::getAttribute( - PlayerInfo::HP)) / static_cast(max), 80, 0, Theme::PROG_HP); - - max = PlayerInfo::getAttribute(PlayerInfo::EXP_NEEDED); - mXpBar = new ProgressBar(this, max ? - static_cast(PlayerInfo::getAttribute(PlayerInfo::EXP)) - / static_cast(max): - static_cast(0), 80, 0, Theme::PROG_EXP); - - const bool magicBar = Net::getGameHandler()->canUseMagicBar(); - const int job = Net::getPlayerHandler()->getJobLocation() - && serverConfig.getValueBool("showJob", true); - - if (magicBar) - { - max = PlayerInfo::getAttribute(PlayerInfo::MAX_MP); - // TRANSLATORS: status window label - mMpLabel = new Label(this, _("MP:")); - mMpBar = new ProgressBar(this, max ? static_cast( - PlayerInfo::getAttribute(PlayerInfo::MAX_MP)) - / static_cast(max) : static_cast(0), - 80, 0, Net::getPlayerHandler()->canUseMagic() ? - Theme::PROG_MP : Theme::PROG_NO_MP); - } - else - { - mMpLabel = nullptr; - mMpBar = nullptr; - } - - place(0, 0, mLvlLabel, 3); - place(0, 1, mHpLabel).setPadding(3); - place(1, 1, mHpBar, 4); - place(5, 1, mXpLabel).setPadding(3); - place(6, 1, mXpBar, 5); - if (magicBar) - { - place(0, 2, mMpLabel).setPadding(3); - // 5, 2 and 6, 2 Job Progress Bar - if (job) - place(1, 2, mMpBar, 4); - else - place(1, 2, mMpBar, 10); - } - - if (job) - { - // TRANSLATORS: status window label - mJobLvlLabel = new Label(this, strprintf(_("Job: %d"), 0)); - // TRANSLATORS: status window label - mJobLabel = new Label(this, _("Job:")); - mJobBar = new ProgressBar(this, 0.0F, 80, 0, Theme::PROG_JOB); - - place(3, 0, mJobLvlLabel, 3); - place(5, 2, mJobLabel).setPadding(3); - place(6, 2, mJobBar, 5); - place(6, 0, mMoneyLabel, 3); - } - else - { - mJobLvlLabel = nullptr; - mJobLabel = nullptr; - mJobBar = nullptr; - place(3, 0, mMoneyLabel, 3); - } - - // ---------------------- - // Stats Part - // ---------------------- - - mAttrScroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); - mAttrScroll->setVerticalScrollPolicy(ScrollArea::SHOW_AUTO); - place(0, 3, mAttrScroll, 5, 3); - - mDAttrScroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); - mDAttrScroll->setVerticalScrollPolicy(ScrollArea::SHOW_AUTO); - place(6, 3, mDAttrScroll, 5, 3); - - getLayout().setRowHeight(3, Layout::AUTO_SET); - - place(0, 6, mCharacterPointsLabel, 5); - place(0, 5, mCopyButton); - - if (Net::getPlayerHandler()->canCorrectAttributes()) - { - mCorrectionPointsLabel = new Label(this, "C"); - place(0, 7, mCorrectionPointsLabel, 5); - } - - loadWindowState(); - enableVisibleSound(true); - - // Update bars - updateHPBar(mHpBar, true); - if (magicBar) - updateMPBar(mMpBar, true); - updateXPBar(mXpBar, false); - - // TRANSLATORS: status window label - mMoneyLabel->setCaption(strprintf(_("Money: %s"), Units::formatCurrency( - PlayerInfo::getAttribute(PlayerInfo::MONEY)).c_str())); - mMoneyLabel->adjustSize(); - // TRANSLATORS: status window label - mCharacterPointsLabel->setCaption(strprintf(_("Character points: %d"), - PlayerInfo::getAttribute(PlayerInfo::CHAR_POINTS))); - mCharacterPointsLabel->adjustSize(); - - if (player_node && player_node->isGM()) - { - // TRANSLATORS: status window label - mLvlLabel->setCaption(strprintf(_("Level: %d (GM %d)"), - PlayerInfo::getAttribute(PlayerInfo::LEVEL), - player_node->getGMLevel())); - } - else - { - // TRANSLATORS: status window label - mLvlLabel->setCaption(strprintf(_("Level: %d"), - PlayerInfo::getAttribute(PlayerInfo::LEVEL))); - } - mLvlLabel->adjustSize(); -} - -void StatusWindow::processEvent(const Channels channel A_UNUSED, - const DepricatedEvent &event) -{ - static bool blocked = false; - if (blocked) - return; - - const DepricatedEvents &eventName = event.getName(); - if (eventName == EVENT_UPDATEATTRIBUTE) - { - switch (event.getInt("id")) - { - case PlayerInfo::HP: - case PlayerInfo::MAX_HP: - updateHPBar(mHpBar, true); - break; - - case PlayerInfo::MP: - case PlayerInfo::MAX_MP: - updateMPBar(mMpBar, true); - break; - - case PlayerInfo::EXP: - case PlayerInfo::EXP_NEEDED: - updateXPBar(mXpBar, false); - break; - - case PlayerInfo::MONEY: - // TRANSLATORS: status window label - mMoneyLabel->setCaption(strprintf(_("Money: %s"), - Units::formatCurrency(event.getInt("newValue")).c_str())); - mMoneyLabel->adjustSize(); - break; - - case PlayerInfo::CHAR_POINTS: - mCharacterPointsLabel->setCaption(strprintf( - // TRANSLATORS: status window label - _("Character points: %d"), event.getInt("newValue"))); - - mCharacterPointsLabel->adjustSize(); - // Update all attributes - for (Attrs::const_iterator it = mAttrs.begin(); - it != mAttrs.end(); ++it) - { - if (it->second) - it->second->update(); - } - break; - - case PlayerInfo::CORR_POINTS: - mCorrectionPointsLabel->setCaption(strprintf( - // TRANSLATORS: status window label - _("Correction points: %d"), event.getInt("newValue"))); - mCorrectionPointsLabel->adjustSize(); - // Update all attributes - for (Attrs::const_iterator it = mAttrs.begin(); - it != mAttrs.end(); ++it) - { - if (it->second) - it->second->update(); - } - break; - - case PlayerInfo::LEVEL: - // TRANSLATORS: status window label - mLvlLabel->setCaption(strprintf(_("Level: %d"), - event.getInt("newValue"))); - mLvlLabel->adjustSize(); - break; - - default: - break; - } - } - else if (eventName == EVENT_UPDATESTAT) - { - const int id = event.getInt("id"); - if (id == Net::getPlayerHandler()->getJobLocation()) - { - if (mJobLvlLabel) - { - int lvl = PlayerInfo::getStatBase(id); - const int oldExp = event.getInt("oldValue1"); - const std::pair exp - = PlayerInfo::getStatExperience(id); - - if (!lvl) - { - // possible server broken and don't send job level, - // then we fixing it :) - if (exp.second < 20000) - { - lvl = 0; - } - else - { - lvl = (exp.second - 20000) / 150; - blocked = true; - PlayerInfo::setStatBase(id, lvl); - blocked = false; - } - } - - if (exp.first < oldExp && exp.second >= 20000) - { // possible job level up. but server broken and don't send - // new job exp limit, we fixing it - lvl ++; - blocked = true; - PlayerInfo::setStatExperience( - id, exp.first, 20000 + lvl * 150); - PlayerInfo::setStatBase(id, lvl); - blocked = false; - } - - // TRANSLATORS: status window label - mJobLvlLabel->setCaption(strprintf(_("Job: %d"), lvl)); - mJobLvlLabel->adjustSize(); - - updateProgressBar(mJobBar, id, false); - } - } - else - { - updateMPBar(mMpBar, true); - const Attrs::const_iterator it = mAttrs.find(id); - if (it != mAttrs.end() && it->second) - it->second->update(); - } - } -} - -void StatusWindow::setPointsNeeded(const int id, const int needed) -{ - const Attrs::const_iterator it = mAttrs.find(id); - - if (it != mAttrs.end()) - { - AttrDisplay *const disp = it->second; - if (disp && disp->getType() == AttrDisplay::CHANGEABLE) - static_cast(disp)->setPointsNeeded(needed); - } -} - -void StatusWindow::addAttribute(const int id, const std::string &name, - const std::string &shortName, - const bool modifiable, - const std::string &description A_UNUSED) -{ - AttrDisplay *disp; - - if (modifiable) - { - disp = new ChangeDisplay(this, id, name, shortName); - mAttrCont->add1(disp); - } - else - { - disp = new DerDisplay(this, id, name, shortName); - mDAttrCont->add1(disp); - } - mAttrs[id] = disp; -} - -void StatusWindow::clearAttributes() -{ - mAttrCont->clear(); - mDAttrCont->clear(); - FOR_EACH (Attrs::iterator, it, mAttrs) - delete (*it).second; - mAttrs.clear(); -} - -void StatusWindow::updateHPBar(ProgressBar *const bar, const bool showMax) -{ - if (!bar) - return; - - const int hp = PlayerInfo::getAttribute(PlayerInfo::HP); - const int maxHp = PlayerInfo::getAttribute(PlayerInfo::MAX_HP); - if (showMax) - bar->setText(toString(hp).append("/").append(toString(maxHp))); - else - bar->setText(toString(hp)); - - float prog = 1.0; - if (maxHp > 0) - prog = static_cast(hp) / static_cast(maxHp); - bar->setProgress(prog); -} - -void StatusWindow::updateMPBar(ProgressBar *const bar, const bool showMax) -{ - if (!bar) - return; - - const int mp = PlayerInfo::getAttribute(PlayerInfo::MP); - const int maxMp = PlayerInfo::getAttribute(PlayerInfo::MAX_MP); - if (showMax) - bar->setText(toString(mp).append("/").append(toString(maxMp))); - else - bar->setText(toString(mp)); - - float prog = 1.0F; - if (maxMp > 0) - prog = static_cast(mp) / static_cast(maxMp); - - if (Net::getPlayerHandler()->canUseMagic()) - bar->setProgressPalette(Theme::PROG_MP); - else - bar->setProgressPalette(Theme::PROG_NO_MP); - - bar->setProgress(prog); -} - -void StatusWindow::updateProgressBar(ProgressBar *const bar, const int value, - const int max, const bool percent) -{ - if (!bar) - return; - - if (max == 0) - { - // TRANSLATORS: status bar label - bar->setText(_("Max")); - bar->setProgress(1); - bar->setText(toString(value)); - } - else - { - const float progress = static_cast(value) - / static_cast(max); - if (percent) - { - bar->setText(strprintf("%2.5f%%", - static_cast(100 * progress))); - } - else - { - bar->setText(toString(value).append("/").append(toString(max))); - } - bar->setProgress(progress); - } -} - -void StatusWindow::updateXPBar(ProgressBar *const bar, const bool percent) -{ - if (!bar) - return; - - updateProgressBar(bar, PlayerInfo::getAttribute(PlayerInfo::EXP), - PlayerInfo::getAttribute(PlayerInfo::EXP_NEEDED), percent); -} - -void StatusWindow::updateJobBar(ProgressBar *const bar, const bool percent) -{ - if (!bar) - return; - - const std::pair exp = PlayerInfo::getStatExperience( - Net::getPlayerHandler()->getJobLocation()); - updateProgressBar(bar, exp.first, exp.second, percent); -} - -void StatusWindow::updateProgressBar(ProgressBar *const bar, const int id, - const bool percent) const -{ - const std::pair exp = PlayerInfo::getStatExperience(id); - updateProgressBar(bar, exp.first, exp.second, percent); -} - -void StatusWindow::updateWeightBar(ProgressBar *const bar) -{ - if (!bar) - return; - - if (PlayerInfo::getAttribute(PlayerInfo::MAX_WEIGHT) == 0) - { - // TRANSLATORS: status bar label - bar->setText(_("Max")); - bar->setProgress(1.0); - } - else - { - const int totalWeight = PlayerInfo::getAttribute( - PlayerInfo::TOTAL_WEIGHT); - const int maxWeight = PlayerInfo::getAttribute(PlayerInfo::MAX_WEIGHT); - const float progress = static_cast(totalWeight) - / static_cast(maxWeight); - bar->setText(strprintf("%s/%s", Units::formatWeight( - totalWeight).c_str(), Units::formatWeight(maxWeight).c_str())); - bar->setProgress(progress); - } -} - -void StatusWindow::updateMoneyBar(ProgressBar *const bar) -{ - if (!bar) - return; - - const int money = PlayerInfo::getAttribute(PlayerInfo::MONEY); - bar->setText(Units::formatCurrency(money).c_str()); - if (money > 0) - { - const float progress = static_cast(money) - / static_cast(1000000000); - bar->setProgress(progress); - } - else - { - bar->setProgress(1.0); - } -} - -void StatusWindow::updateArrowsBar(ProgressBar *const bar) -{ - if (!bar || !equipmentWindow) - return; - - const Item *const item = equipmentWindow->getEquipment( - Equipment::EQUIP_PROJECTILE_SLOT); - - if (item && item->getQuantity() > 0) - bar->setText(toString(item->getQuantity())); - else - bar->setText("0"); -} - -void StatusWindow::updateInvSlotsBar(ProgressBar *const bar) -{ - if (!bar) - return; - - const Inventory *const inv = PlayerInfo::getInventory(); - if (!inv) - return; - - const int usedSlots = inv->getNumberOfSlotsUsed(); - const int maxSlots = inv->getSize(); - - if (maxSlots) - { - bar->setProgress(static_cast(usedSlots) - / static_cast(maxSlots)); - } - - bar->setText(strprintf("%d", usedSlots)); -} - -std::string StatusWindow::translateLetter(const char *const letters) -{ - char buf[2]; - char *const str = gettext(letters); - if (strlen(str) != 3) - return letters; - - buf[0] = str[1]; - buf[1] = 0; - return std::string(buf); -} - -std::string StatusWindow::translateLetter2(std::string letters) -{ - if (letters.size() < 5) - return ""; - - return std::string(gettext(letters.substr(1, 1).c_str())); -} - -void StatusWindow::updateStatusBar(ProgressBar *const bar, - const bool percent A_UNUSED) -{ - if (!player_node || !viewport) - return; - - bar->setText(translateLetter2(player_node->getInvertDirectionString()) - .append(translateLetter2(player_node->getCrazyMoveTypeString())) - .append(translateLetter2(player_node->getMoveToTargetTypeString())) - .append(translateLetter2(player_node->getFollowModeString())) - .append(" ").append(translateLetter2( - player_node->getAttackWeaponTypeString())) - .append(translateLetter2(player_node->getAttackTypeString())) - .append(translateLetter2(player_node->getMagicAttackString())) - .append(translateLetter2(player_node->getPvpAttackString())) - .append(" ").append(translateLetter2( - player_node->getQuickDropCounterString())) - .append(translateLetter2(player_node->getPickUpTypeString())) - .append(" ").append(translateLetter2( - player_node->getDebugPathString())) - .append(" ").append(translateLetter2( - player_node->getImitationModeString())) - .append(translateLetter2(player_node->getCameraModeString())) - .append(translateLetter2(player_node->getAwayModeString()))); - - bar->setProgress(50); - if (player_node->getDisableGameModifiers()) - bar->setColor(Theme::getThemeColor(Theme::STATUSBAR_ON)); - else - bar->setColor(Theme::getThemeColor(Theme::STATUSBAR_OFF)); -} - -void StatusWindow::action(const gcn::ActionEvent &event) -{ - if (!chatWindow) - return; - - if (event.getId() == "copy") - { - Attrs::const_iterator it = mAttrs.begin(); - const Attrs::const_iterator it_end = mAttrs.end(); - std::string str; - while (it != it_end) - { - const ChangeDisplay *const attr = dynamic_cast( - (*it).second); - if (attr) - { - str.append(strprintf("%s:%s ", attr->getShortName().c_str(), - attr->getValue().c_str())); - } - ++ it; - } - chatWindow->addInputText(str); - } -} - -AttrDisplay::AttrDisplay(const Widget2 *const widget, - const int id, const std::string &name, - const std::string &shortName) : - Container(widget), - mId(id), - mName(name), - mShortName(shortName), - mLayout(new LayoutHelper(this)), - mLabel(new Label(this, name)), - mValue(new Label(this, "1 ")) -{ - setSize(100, 32); - - mLabel->setAlignment(Graphics::CENTER); - mValue->setAlignment(Graphics::CENTER); -} - -AttrDisplay::~AttrDisplay() -{ - delete mLayout; - mLayout = nullptr; -} - -std::string AttrDisplay::update() -{ - const int base = PlayerInfo::getStatBase(mId); - const int bonus = PlayerInfo::getStatMod(mId); - std::string value = toString(base + bonus); - if (bonus) - value.append(strprintf("=%d%+d", base, bonus)); - mValue->setCaption(value); - return mName; -} - -DerDisplay::DerDisplay(const Widget2 *const widget, - const int id, const std::string &name, - const std::string &shortName) : - AttrDisplay(widget, id, name, shortName) -{ - ContainerPlacer place = mLayout->getPlacer(0, 0); - - place(0, 0, mLabel, 3); - place(3, 0, mValue, 2); - - update(); -} - -ChangeDisplay::ChangeDisplay(const Widget2 *const widget, - const int id, const std::string &name, - const std::string &shortName) : - AttrDisplay(widget, id, name, shortName), - gcn::ActionListener(), - mNeeded(1), - // TRANSLATORS: status window label - mPoints(new Label(this, _("Max"))), - mDec(nullptr), - // TRANSLATORS: status window label (plus sign) - mInc(new Button(this, _("+"), "inc", this)) -{ - // Do the layout - ContainerPlacer place = mLayout->getPlacer(0, 0); - - place(0, 0, mLabel, 3); - place(4, 0, mValue, 2); - place(6, 0, mInc); - place(7, 0, mPoints); - - if (Net::getPlayerHandler()->canCorrectAttributes()) - { - // TRANSLATORS: status window label (minus sign) - mDec = new Button(this, _("-"), "dec", this); - mDec->setWidth(mInc->getWidth()); - - place(3, 0, mDec); - } - - update(); -} - -std::string ChangeDisplay::update() -{ - if (mNeeded > 0) - { - mPoints->setCaption(toString(mNeeded)); - } - else - { - // TRANSLATORS: status bar label - mPoints->setCaption(_("Max")); - } - - if (mDec) - mDec->setEnabled(PlayerInfo::getAttribute(PlayerInfo::CORR_POINTS)); - - mInc->setEnabled(PlayerInfo::getAttribute(PlayerInfo::CHAR_POINTS) - >= mNeeded && mNeeded > 0); - - return AttrDisplay::update(); -} - -void ChangeDisplay::setPointsNeeded(const int needed) -{ - mNeeded = needed; - update(); -} - -void ChangeDisplay::action(const gcn::ActionEvent &event) -{ - if (Net::getPlayerHandler()->canCorrectAttributes() && - event.getSource() == mDec) - { - const int newcorrpoints = PlayerInfo::getAttribute( - PlayerInfo::CORR_POINTS); - PlayerInfo::setAttribute(PlayerInfo::CORR_POINTS, newcorrpoints - 1); - - const int newpoints = PlayerInfo::getAttribute( - PlayerInfo::CHAR_POINTS) + 1; - PlayerInfo::setAttribute(PlayerInfo::CHAR_POINTS, newpoints); - - const int newbase = PlayerInfo::getStatBase(mId) - 1; - PlayerInfo::setStatBase(mId, newbase); - - Net::getPlayerHandler()->decreaseAttribute(mId); - } - else if (event.getSource() == mInc) - { - int cnt = 1; - if (config.getBoolValue("quickStats")) - { - cnt = mInc->getClickCount(); - if (cnt > 10) - cnt = 10; - } - - const int newpoints = PlayerInfo::getAttribute( - PlayerInfo::CHAR_POINTS) - cnt; - PlayerInfo::setAttribute(PlayerInfo::CHAR_POINTS, newpoints); - - const int newbase = PlayerInfo::getStatBase(mId) + cnt; - PlayerInfo::setStatBase(mId, newbase); - - for (unsigned f = 0; f < mInc->getClickCount(); f ++) - { - Net::getPlayerHandler()->increaseAttribute(mId); - if (cnt != 1) - SDL_Delay(100); - } - } -} diff --git a/src/gui/statuswindow.h b/src/gui/statuswindow.h deleted file mode 100644 index eebcd12ca..000000000 --- a/src/gui/statuswindow.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_STATUSWINDOW_H -#define GUI_STATUSWINDOW_H - -#include "depricatedlistener.h" - -#include "gui/widgets/window.h" - -#include - -#include - -class AttrDisplay; -class Button; -class Label; -class ProgressBar; -class ScrollArea; -class VertContainer; - -/** - * The player status dialog. - * - * \ingroup Interface - */ -class StatusWindow final : public Window, - public gcn::ActionListener, - public DepricatedListener -{ - public: - /** - * Constructor. - */ - StatusWindow(); - - A_DELETE_COPY(StatusWindow) - - void processEvent(const Channels channel, - const DepricatedEvent &event) override; - - void setPointsNeeded(const int id, const int needed); - - void addAttribute(const int id, const std::string &name, - const std::string &shortName = "", - const bool modifiable = false, - const std::string &description = ""); - - static void updateHPBar(ProgressBar *const bar, - const bool showMax = false); - static void updateMPBar(ProgressBar *bar, bool showMax = false); - static void updateJobBar(ProgressBar *const bar, - const bool percent = true); - static void updateXPBar(ProgressBar *const bar, - const bool percent = true); - static void updateWeightBar(ProgressBar *const bar); - static void updateInvSlotsBar(ProgressBar *const bar); - static void updateMoneyBar(ProgressBar *const bar); - static void updateArrowsBar(ProgressBar *const bar); - static void updateStatusBar(ProgressBar *const bar, - const bool percent = true); - static void updateProgressBar(ProgressBar *const bar, const int value, - const int max, const bool percent); - void updateProgressBar(ProgressBar *const bar, const int id, - const bool percent = true) const; - - void action(const gcn::ActionEvent &event) override; - - void clearAttributes(); - - private: - static std::string translateLetter(const char *const letters); - static std::string translateLetter2(std::string letters); - - /** - * Status Part - */ - Label *mLvlLabel; - Label *mMoneyLabel; - Label *mHpLabel; - Label *mMpLabel; - Label *mXpLabel; - ProgressBar *mHpBar; - ProgressBar *mMpBar; - ProgressBar *mXpBar; - - Label *mJobLvlLabel; - Label *mJobLabel; - ProgressBar *mJobBar; - - VertContainer *mAttrCont; - ScrollArea *mAttrScroll; - VertContainer *mDAttrCont; - ScrollArea *mDAttrScroll; - - Label *mCharacterPointsLabel; - Label *mCorrectionPointsLabel; - Button *mCopyButton; - - typedef std::map Attrs; - Attrs mAttrs; -}; - -extern StatusWindow *statusWindow; - -#endif // GUI_STATUSWINDOW_H diff --git a/src/gui/textcommandeditor.cpp b/src/gui/textcommandeditor.cpp deleted file mode 100644 index d960f20f7..000000000 --- a/src/gui/textcommandeditor.cpp +++ /dev/null @@ -1,396 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 Andrei Karas - * Copyright (C) 2011-2013 The ManaPlus developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/textcommandeditor.h" - -#include "main.h" -#include "spellmanager.h" - -#include "input/keyboardconfig.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/dropdown.h" -#include "gui/widgets/inttextfield.h" -#include "gui/widgets/label.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/radiobutton.h" - -#include "utils/gettext.h" - -#include "resources/itemdb.h" -#include "resources/iteminfo.h" - -#include "debug.h" - -class IconsModal final : public gcn::ListModel -{ -public: - IconsModal() : - mStrings() - { - const std::map &items = ItemDB::getItemInfos(); - std::list tempStrings; - - for (std::map::const_iterator - i = items.begin(), i_end = items.end(); - i != i_end; ++i) - { - if (i->first < 0) - continue; - - const ItemInfo &info = (*i->second); - const std::string name = info.getName(); - if (name != "unnamed" && !info.getName().empty() - && info.getName() != "unnamed") - { - tempStrings.push_back(name); - } - } - tempStrings.sort(); - mStrings.push_back(""); - FOR_EACH (std::list::const_iterator, i, tempStrings) - mStrings.push_back(*i); - } - - A_DELETE_COPY(IconsModal) - - ~IconsModal() - { } - - int getNumberOfElements() override - { - return static_cast(mStrings.size()); - } - - std::string getElementAt(int i) override - { - if (i < 0 || i >= getNumberOfElements()) - return "???"; - return mStrings.at(i); - } -private: - StringVect mStrings; -}; - - -const char *TARGET_TYPE_TEXT[3] = -{ - // TRANSLATORS: target type - N_("No Target"), - // TRANSLATORS: target type - N_("Allow Target"), - // TRANSLATORS: target type - N_("Need Target"), -}; - -const char *MAGIC_SCHOOL_TEXT[6] = -{ - // TRANSLATORS: magic school - N_("General Magic"), - // TRANSLATORS: magic school - N_("Life Magic"), - // TRANSLATORS: magic school - N_("War Magic"), - // TRANSLATORS: magic school - N_("Transmute Magic"), - // TRANSLATORS: magic school - N_("Nature Magic"), - // TRANSLATORS: magic school - N_("Astral Magic") -}; - -class TargetTypeModel final : public gcn::ListModel -{ -public: - ~TargetTypeModel() - { } - - int getNumberOfElements() override - { - return 3; - } - - std::string getElementAt(int i) override - { - if (i >= getNumberOfElements() || i < 0) - return "???"; - return TARGET_TYPE_TEXT[i]; - } -}; - -class MagicSchoolModel final : public gcn::ListModel -{ -public: - ~MagicSchoolModel() - { } - - int getNumberOfElements() override - { - return 6; - } - - std::string getElementAt(int i) override - { - if (i >= getNumberOfElements() || i < 0) - return "???"; - return MAGIC_SCHOOL_TEXT[i]; - } -}; - -TextCommandEditor::TextCommandEditor(TextCommand *const command) : - // TRANSLATORS: command editor name - Window(_("Command Editor"), false, nullptr, "commandeditor.xml"), - gcn::ActionListener(), - mIsMagicCommand(command->getCommandType() == TEXT_COMMAND_MAGIC), - mCommand(command), - // TRANSLATORS: command editor button - mIsMagic(new RadioButton(this, _("magic"), "magic", mIsMagicCommand)), - // TRANSLATORS: command editor button - mIsOther(new RadioButton(this, _("other"), "magic", !mIsMagicCommand)), - // TRANSLATORS: command editor label - mSymbolLabel(new Label(this, _("Symbol:"))), - mSymbolTextField(new TextField(this)), - // TRANSLATORS: command editor label - mCommandLabel(new Label(this, _("Command:"))), - mCommandTextField(new TextField(this)), - // TRANSLATORS: command editor label - mCommentLabel(new Label(this, _("Comment:"))), - mCommentTextField(new TextField(this)), - mTargetTypeModel(new TargetTypeModel), - // TRANSLATORS: command editor label - mTypeLabel(new Label(this, _("Target Type:"))), - mTypeDropDown(new DropDown(this, mTargetTypeModel)), - mIconsModal(new IconsModal), - // TRANSLATORS: command editor label - mIconLabel(new Label(this, _("Icon:"))), - mIconDropDown(new DropDown(this, mIconsModal)), - // TRANSLATORS: command editor label - mManaLabel(new Label(this, _("Mana:"))), - mManaField(new IntTextField(this, 0)), - // TRANSLATORS: command editor label - mMagicLvlLabel(new Label(this, _("Magic level:"))), - mMagicLvlField(new IntTextField(this, 0)), - mMagicSchoolModel(new MagicSchoolModel), - // TRANSLATORS: command editor label - mSchoolLabel(new Label(this, _("Magic School:"))), - mSchoolDropDown(new DropDown(this, mMagicSchoolModel)), - // TRANSLATORS: command editor label - mSchoolLvlLabel(new Label(this, _("School level:"))), - mSchoolLvlField(new IntTextField(this, 0)), - // TRANSLATORS: command editor button - mCancelButton(new Button(this, _("Cancel"), "cancel", this)), - // TRANSLATORS: command editor button - mSaveButton(new Button(this, _("Save"), "save", this)), - // TRANSLATORS: command editor button - mDeleteButton(new Button(this, _("Delete"), "delete", this)), - mEnabledKeyboard(keyboard.isEnabled()) -{ - const int w = 350; - const int h = 370; - - keyboard.setEnabled(false); - - setWindowName("TextCommandEditor"); - setDefaultSize(w, h, ImageRect::CENTER); - - mIsMagic->setActionEventId("magic"); - mIsMagic->addActionListener(this); - - mIsOther->setActionEventId("other"); - mIsOther->addActionListener(this); - - mManaField->setRange(0, 500); - mManaField->setWidth(20); - - mTypeDropDown->setActionEventId("type"); - mTypeDropDown->addActionListener(this); - - mIconDropDown->setActionEventId("icon"); - mIconDropDown->addActionListener(this); - mIconDropDown->setSelectedString(mCommand->getIcon()); - - mMagicLvlField->setRange(0, 5); - mMagicLvlField->setWidth(20); - - mSchoolDropDown->setActionEventId("school"); - mSchoolDropDown->addActionListener(this); - mSchoolDropDown->setSelected(0); - - mSchoolLvlField->setRange(0, 5); - mSchoolLvlField->setWidth(20); - - mSaveButton->adjustSize(); - mCancelButton->adjustSize(); - mDeleteButton->adjustSize(); - - if (command->getCommandType() == TEXT_COMMAND_MAGIC) - showControls(true); - else - showControls(false); - - mSymbolTextField->setText(command->getSymbol()); - mCommandTextField->setText(command->getCommand()); - mCommentTextField->setText(command->getComment()); - mManaField->setValue(command->getMana()); - mTypeDropDown->setSelected(command->getTargetType()); - mMagicLvlField->setValue(command->getBaseLvl()); - mSchoolDropDown->setSelected(command->getSchool() - MAGIC_START_ID); - mSchoolLvlField->setValue(command->getSchoolLvl()); - - ContainerPlacer placer; - placer = getPlacer(0, 0); - - placer(0, 0, mIsMagic, 1); - placer(2, 0, mIsOther, 1); - placer(0, 1, mSymbolLabel, 2).setPadding(3); - placer(2, 1, mSymbolTextField, 3).setPadding(3); - placer(0, 2, mCommandLabel, 2).setPadding(3); - placer(2, 2, mCommandTextField, 4).setPadding(3); - - placer(0, 3, mCommentLabel, 2).setPadding(3); - placer(2, 3, mCommentTextField, 4).setPadding(3); - - placer(0, 4, mTypeLabel, 2).setPadding(3); - placer(2, 4, mTypeDropDown, 3).setPadding(3); - - placer(0, 5, mIconLabel, 2).setPadding(3); - placer(2, 5, mIconDropDown, 3).setPadding(3); - - placer(0, 6, mManaLabel, 2).setPadding(3); - placer(2, 6, mManaField, 3).setPadding(3); - placer(0, 7, mMagicLvlLabel, 2).setPadding(3); - placer(2, 7, mMagicLvlField, 3).setPadding(3); - - placer(0, 8, mSchoolLabel, 2).setPadding(3); - placer(2, 8, mSchoolDropDown, 3).setPadding(3); - placer(0, 9, mSchoolLvlLabel, 2).setPadding(3); - placer(2, 9, mSchoolLvlField, 3).setPadding(3); - - placer(0, 10, mSaveButton, 2).setPadding(3); - placer(2, 10, mCancelButton, 2).setPadding(3); - placer(4, 10, mDeleteButton, 2).setPadding(3); - - setWidth(w); - setHeight(h); - - reflowLayout(w); - - center(); - - enableVisibleSound(true); - setVisible(true); -} - -TextCommandEditor::~TextCommandEditor() -{ - delete mIconsModal; - mIconsModal = nullptr; - delete mTargetTypeModel; - mTargetTypeModel = nullptr; - delete mMagicSchoolModel; - mMagicSchoolModel = nullptr; -} - -void TextCommandEditor::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "magic") - { - mIsMagicCommand = true; - showControls(true); - } - else if (eventId == "other") - { - mIsMagicCommand = false; - showControls(false); - } - else if (eventId == "save") - { - save(); - scheduleDelete(); - } - else if (eventId == "cancel") - { - scheduleDelete(); - } - else if (eventId == "delete") - { - deleteCommand(); - scheduleDelete(); - } -} - -void TextCommandEditor::showControls(const bool show) -{ - mManaField->setVisible(show); - mManaLabel->setVisible(show); - mMagicLvlLabel->setVisible(show); - mMagicLvlField->setVisible(show); - mSchoolLabel->setVisible(show); - mSchoolDropDown->setVisible(show); - mSchoolLvlLabel->setVisible(show); - mSchoolLvlField->setVisible(show); -} - -void TextCommandEditor::scheduleDelete() -{ - keyboard.setEnabled(mEnabledKeyboard); - Window::scheduleDelete(); -} - -void TextCommandEditor::save() -{ - if (mIsMagicCommand) - mCommand->setCommandType(TEXT_COMMAND_MAGIC); - else - mCommand->setCommandType(TEXT_COMMAND_TEXT); - - mCommand->setSymbol(mSymbolTextField->getText()); - mCommand->setCommand(mCommandTextField->getText()); - mCommand->setComment(mCommentTextField->getText()); - mCommand->setMana(mManaField->getValue()); - mCommand->setTargetType( - static_cast(mTypeDropDown->getSelected())); - mCommand->setIcon(mIconDropDown->getSelectedString()); - mCommand->setBaseLvl(mMagicLvlField->getValue()); - mCommand->setSchool(static_cast( - mSchoolDropDown->getSelected() + MAGIC_START_ID)); - mCommand->setSchoolLvl(mSchoolLvlField->getValue()); - if (spellManager) - spellManager->save(); -} - -void TextCommandEditor::deleteCommand() -{ - mCommand->setCommandType(TEXT_COMMAND_TEXT); - mCommand->setSymbol(""); - mCommand->setCommand(""); - mCommand->setComment(""); - mCommand->setMana(0); - mCommand->setTargetType(NOTARGET); - mCommand->setIcon(""); - mCommand->setBaseLvl(0); - mCommand->setSchool(SKILL_MAGIC); - mCommand->setSchoolLvl(0); - if (spellManager) - spellManager->save(); -} diff --git a/src/gui/textcommandeditor.h b/src/gui/textcommandeditor.h deleted file mode 100644 index 610b014d5..000000000 --- a/src/gui/textcommandeditor.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 Andrei Karas - * Copyright (C) 2011-2013 The ManaPlus developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_TEXTCOMMANDEDITOR_H -#define GUI_TEXTCOMMANDEDITOR_H - -#include "gui/widgets/window.h" - -#include - -class Button; -class DropDown; -class IconsModal; -class IntTextField; -class Label; -class MagicSchoolModel; -class RadioButton; -class TargetTypeModel; -class TextCommand; -class TextField; - -class TextCommandEditor final : public Window, public gcn::ActionListener -{ - public: - /** - * Constructor. - */ - explicit TextCommandEditor(TextCommand *const command); - - A_DELETE_COPY(TextCommandEditor) - - /** - * Destructor. - */ - ~TextCommandEditor(); - - void action(const gcn::ActionEvent &event) override; - - void scheduleDelete() override; - - private: - void showControls(const bool show); - - void save(); - - void deleteCommand(); - - bool mIsMagicCommand; - TextCommand *mCommand; - - RadioButton *mIsMagic; - RadioButton *mIsOther; - Label *mSymbolLabel; - TextField *mSymbolTextField; - Label *mCommandLabel; - TextField *mCommandTextField; - - Label *mCommentLabel; - TextField *mCommentTextField; - - TargetTypeModel *mTargetTypeModel; - Label *mTypeLabel; - DropDown *mTypeDropDown; - IconsModal *mIconsModal; - Label *mIconLabel; - DropDown *mIconDropDown; - Label *mManaLabel; - IntTextField *mManaField; - Label *mMagicLvlLabel; - IntTextField *mMagicLvlField; - MagicSchoolModel *mMagicSchoolModel; - Label *mSchoolLabel; - DropDown *mSchoolDropDown; - Label *mSchoolLvlLabel; - IntTextField *mSchoolLvlField; - - Button *mCancelButton; - Button *mSaveButton; - Button *mDeleteButton; - - bool mEnabledKeyboard; -}; - -#endif // GUI_TEXTCOMMANDEDITOR_H diff --git a/src/gui/textdialog.cpp b/src/gui/textdialog.cpp deleted file mode 100644 index 3b26ec2de..000000000 --- a/src/gui/textdialog.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/textdialog.h" - -#include "input/keyboardconfig.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/label.h" -#include "gui/widgets/passwordfield.h" - -#include "utils/gettext.h" - -#include - -#include "debug.h" - -int TextDialog::instances = 0; - -TextDialog::TextDialog(const std::string &title, const std::string &msg, - Window *const parent, const bool isPassword): - Window(title, true, parent, "textdialog.xml"), - gcn::ActionListener(), - mTextField(nullptr), - mPasswordField(nullptr), - // TRANSLATORS: text dialog button - mOkButton(new Button(this, _("OK"), "OK", this)), - mEnabledKeyboard(keyboard.isEnabled()) -{ - keyboard.setEnabled(false); - - Label *const textLabel = new Label(this, msg); - // TRANSLATORS: text dialog button - Button *const cancelButton = new Button(this, _("Cancel"), "CANCEL", this); - - place(0, 0, textLabel, 4); - if (isPassword) - { - mPasswordField = new PasswordField(this); - place(0, 1, mPasswordField, 4); - } - else - { - mTextField = new TextField(this); - place(0, 1, mTextField, 4); - } - place(2, 2, mOkButton); - place(3, 2, cancelButton); - - const gcn::Font *const font = getFont(); - if (font) - { - int width = font->getWidth(title); - if (width < textLabel->getWidth()) - width = textLabel->getWidth(); - reflowLayout(static_cast(width + 20)); - } - else - { - reflowLayout(static_cast(textLabel->getWidth() + 20)); - } - - if (getParent()) - { - setLocationRelativeTo(getParent()); - getParent()->moveToTop(this); - } - setVisible(true); - requestModalFocus(); - if (isPassword) - mPasswordField->requestFocus(); - else - mTextField->requestFocus(); - - instances++; -} - -TextDialog::~TextDialog() -{ - instances--; -} - -void TextDialog::action(const gcn::ActionEvent &event) -{ - if (event.getId() == "CANCEL") - setActionEventId("~" + getActionEventId()); - - distributeActionEvent(); - close(); -} - -const std::string &TextDialog::getText() const -{ - if (mTextField) - return mTextField->getText(); - else - return mPasswordField->getText(); -} - -void TextDialog::setText(const std::string &text) -{ - if (mTextField) - mTextField->setText(text); - else - mPasswordField->setText(text); -} - -void TextDialog::close() -{ - keyboard.setEnabled(mEnabledKeyboard); - scheduleDelete(); -} diff --git a/src/gui/textdialog.h b/src/gui/textdialog.h deleted file mode 100644 index 9f9292ef6..000000000 --- a/src/gui/textdialog.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_TEXTDIALOG_H -#define GUI_TEXTDIALOG_H - -#include "gui/widgets/window.h" - -#include - -class Button; -class PasswordField; -class TextField; - -/** -* An option dialog. - * - * \ingroup GUI - */ -class TextDialog final : public Window, public gcn::ActionListener -{ -public: - /** - * Constructor. - * - * @see Window::Window - */ - TextDialog(const std::string &title, const std::string &msg, - Window *const parent = nullptr, const bool isPassword = false); - - A_DELETE_COPY(TextDialog) - - ~TextDialog(); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - /** - * Get the text in the textfield - */ - const std::string &getText() const A_WARN_UNUSED; - - void setText(const std::string &text); - - static bool isActive() A_WARN_UNUSED - { return instances; } - - void close() override; - -private: - static int instances; - - TextField *mTextField; - PasswordField *mPasswordField; - Button *mOkButton; - bool mEnabledKeyboard; -}; - -#endif // GUI_TEXTDIALOG_H diff --git a/src/gui/tradewindow.cpp b/src/gui/tradewindow.cpp deleted file mode 100644 index e56b28913..000000000 --- a/src/gui/tradewindow.cpp +++ /dev/null @@ -1,485 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/tradewindow.h" - -#include "configuration.h" -#include "inventory.h" -#include "item.h" -#include "units.h" - -#include "being/localplayer.h" -#include "being/playerinfo.h" -#include "being/playerrelations.h" - -#include "gui/gui.h" -#include "gui/inventorywindow.h" -#include "gui/itemamountwindow.h" -#include "gui/sdlfont.h" -#include "gui/setup.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/chattab.h" -#include "gui/widgets/itemcontainer.h" -#include "gui/widgets/label.h" -#include "gui/widgets/scrollarea.h" -#include "gui/widgets/textfield.h" -#include "gui/widgets/layout.h" - -#include "net/net.h" -#include "net/tradehandler.h" - -#include "utils/gettext.h" - -#include - -#include "debug.h" - -// TRANSLATORS: trade window button -#define CAPTION_PROPOSE _("Propose trade") -// TRANSLATORS: trade window button -#define CAPTION_CONFIRMED _("Confirmed. Waiting...") -// TRANSLATORS: trade window button -#define CAPTION_ACCEPT _("Agree trade") -// TRANSLATORS: trade window button -#define CAPTION_ACCEPTED _("Agreed. Waiting...") - -TradeWindow::TradeWindow(): - // TRANSLATORS: trade window caption - Window(_("Trade: You"), false, nullptr, "trade.xml"), - gcn::ActionListener(), - gcn::SelectionListener(), - mMyInventory(new Inventory(Inventory::TRADE)), - mPartnerInventory(new Inventory(Inventory::TRADE)), - mMyItemContainer(new ItemContainer(this, mMyInventory.get())), - mPartnerItemContainer(new ItemContainer(this, mPartnerInventory.get())), - // TRANSLATORS: trade window money label - mMoneyLabel(new Label(this, strprintf(_("You get %s"), ""))), - // TRANSLATORS: trade window button - mAddButton(new Button(this, _("Add"), "add", this)), - mOkButton(new Button(this, "", "", this)), // Will be filled in later - // TRANSLATORS: trade window money change button - mMoneyChangeButton(new Button(this, _("Change"), "money", this)), - mMoneyField(new TextField(this)), - mStatus(PROPOSING), - mAutoAddItem(nullptr), - mAutoAddToNick(""), - mGotMoney(0), - mGotMaxMoney(0), - mAutoMoney(0), - mAutoAddAmount(0), - mOkOther(false), - mOkMe(false) -{ - setWindowName("Trade"); - setResizable(true); - setCloseButton(true); - setStickyButtonLock(true); - setDefaultSize(386, 180, ImageRect::CENTER); - setMinWidth(310); - setMinHeight(180); - - if (setupWindow) - setupWindow->registerWindowForReset(this); - - const gcn::Font *const fnt = mOkButton->getFont(); - int width = std::max(fnt->getWidth(CAPTION_PROPOSE), - fnt->getWidth(CAPTION_CONFIRMED)); - width = std::max(width, fnt->getWidth(CAPTION_ACCEPT)); - width = std::max(width, fnt->getWidth(CAPTION_ACCEPTED)); - - mOkButton->setWidth(8 + width); - - mMyItemContainer->addSelectionListener(this); - - ScrollArea *const myScroll = new ScrollArea(mMyItemContainer, - true, "trade_background.xml"); - myScroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); - - mPartnerItemContainer->addSelectionListener(this); - - ScrollArea *const partnerScroll = new ScrollArea(mPartnerItemContainer, - true, "trade_background.xml"); - partnerScroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); - - // TRANSLATORS: trade window money label - Label *const moneyLabel2 = new Label(this, _("You give:")); - - mMoneyField->setWidth(40); - - place(1, 0, mMoneyLabel); - place(0, 1, myScroll).setPadding(3); - place(1, 1, partnerScroll).setPadding(3); - ContainerPlacer placer; - placer = getPlacer(0, 0); - placer(0, 0, moneyLabel2); - placer(1, 0, mMoneyField, 2); - placer(3, 0, mMoneyChangeButton).setHAlign(LayoutCell::LEFT); - placer = getPlacer(0, 2); - placer(0, 0, mAddButton); - placer(1, 0, mOkButton); - Layout &layout = getLayout(); - layout.extend(0, 2, 2, 1); - layout.setRowHeight(1, Layout::AUTO_SET); - layout.setRowHeight(2, 0); - layout.setColWidth(0, Layout::AUTO_SET); - layout.setColWidth(1, Layout::AUTO_SET); - - loadWindowState(); - enableVisibleSound(true); - - reset(); -} - -TradeWindow::~TradeWindow() -{ -} - -void TradeWindow::setMoney(const int amount) -{ - if (amount < 0 || amount < mGotMaxMoney) - { - if (config.getBoolValue("securetrades")) - { - close(); - return; - } - else - { - mMoneyLabel->setForegroundColorAll(getThemeColor( - static_cast(Theme::WARNING)), getThemeColor( - static_cast(Theme::WARNING_OUTLINE))); - } - } - else - { - mMoneyLabel->setForegroundColorAll(getThemeColor( - static_cast(Theme::LABEL)), getThemeColor( - static_cast(Theme::LABEL_OUTLINE))); - mGotMaxMoney = amount; - } - - mGotMoney = amount; - // TRANSLATORS: trade window money label - mMoneyLabel->setCaption(strprintf(_("You get %s"), - Units::formatCurrency(amount).c_str())); - mMoneyLabel->adjustSize(); -} - -void TradeWindow::addItem(const int id, const bool own, const int quantity, - const int refine, const unsigned char color) const -{ - if (own) - mMyInventory->addItem(id, quantity, refine, color); - else - mPartnerInventory->addItem(id, quantity, refine, color); -} - -void TradeWindow::addItem2(const int id, const bool own, const int quantity, - const int refine, const unsigned char color, - const bool equipment) const -{ - if (own) - mMyInventory->addItem(id, quantity, refine, color, equipment); - else - mPartnerInventory->addItem(id, quantity, refine, color, equipment); -} - -void TradeWindow::changeQuantity(const int index, const bool own, - const int quantity) const -{ - Item *item; - if (own) - item = mMyInventory->getItem(index); - else - item = mPartnerInventory->getItem(index); - if (item) - item->setQuantity(quantity); -} - -void TradeWindow::increaseQuantity(const int index, const bool own, - const int quantity) const -{ - Item *item; - if (own) - item = mMyInventory->getItem(index); - else - item = mPartnerInventory->getItem(index); - if (item) - item->increaseQuantity(quantity); -} - -void TradeWindow::reset() -{ - mMyInventory->clear(); - mPartnerInventory->clear(); - mOkOther = false; - mOkMe = false; - setMoney(0); - mMoneyField->setEnabled(true); - mMoneyField->setText(""); - mMoneyLabel->setForegroundColorAll(getThemeColor( - static_cast(Theme::LABEL)), getThemeColor( - static_cast(Theme::LABEL_OUTLINE))); - mAddButton->setEnabled(true); - mMoneyChangeButton->setEnabled(true); - mGotMoney = 0; - mGotMaxMoney = 0; - setStatus(PREPARING); -} - -void TradeWindow::receivedOk(const bool own) -{ - if (own) - mOkMe = true; - else - mOkOther = true; - - if (mOkMe && mOkOther) - setStatus(ACCEPTING); -} - -void TradeWindow::tradeItem(const Item *const item, const int quantity, - const bool check) const -{ - if (check && !checkItem(item)) - return; - - Net::getTradeHandler()->addItem(item, quantity); -} - -void TradeWindow::valueChanged(const gcn::SelectionEvent &event) -{ - if (!mMyItemContainer || !mPartnerItemContainer) - return; - - /* If an item is selected in one container, make sure no item is selected - * in the other container. - */ - if (event.getSource() == mMyItemContainer && - mMyItemContainer->getSelectedItem()) - { - mPartnerItemContainer->selectNone(); - } - else if (mPartnerItemContainer->getSelectedItem()) - { - mMyItemContainer->selectNone(); - } -} - -void TradeWindow::setStatus(const Status s) -{ - if (s == mStatus) - return; - mStatus = s; - - switch (s) - { - case PREPARING: - mOkButton->setCaption(CAPTION_PROPOSE); - mOkButton->setActionEventId("ok"); - break; - case PROPOSING: - mOkButton->setCaption(CAPTION_CONFIRMED); - mOkButton->setActionEventId(""); - break; - case ACCEPTING: - mOkButton->setCaption(CAPTION_ACCEPT); - mOkButton->setActionEventId("trade"); - break; - case ACCEPTED: - mOkButton->setCaption(CAPTION_ACCEPTED); - mOkButton->setActionEventId(""); - break; - default: - break; - } - - mOkButton->setEnabled((s != PROPOSING && s != ACCEPTED)); -} - -void TradeWindow::action(const gcn::ActionEvent &event) -{ - if (!inventoryWindow) - return; - - Item *const item = inventoryWindow->getSelectedItem(); - const std::string &eventId = event.getId(); - - if (eventId == "add") - { - if (mStatus != PREPARING) - return; - - if (!inventoryWindow->isWindowVisible()) - { - inventoryWindow->setVisible(true); - return; - } - - if (!item) - return; - - if (mMyInventory->getFreeSlot() == -1) - return; - - - if (!checkItem(item)) - return; - - // Choose amount of items to trade - ItemAmountWindow::showWindow(ItemAmountWindow::TradeAdd, this, item); - - setStatus(PREPARING); - } - else if (eventId == "cancel") - { - setVisible(false); - reset(); - PlayerInfo::setTrading(false); - Net::getTradeHandler()->cancel(); - } - else if (eventId == "ok") - { - mMoneyField->setEnabled(false); - mAddButton->setEnabled(false); - mMoneyChangeButton->setEnabled(false); - receivedOk(true); - setStatus(PROPOSING); - Net::getTradeHandler()->confirm(); - } - else if (eventId == "trade") - { - receivedOk(true); - setStatus(ACCEPTED); - Net::getTradeHandler()->finish(); - } - else if (eventId == "money") - { - if (mStatus != PREPARING) - return; - - int v = atoi(mMoneyField->getText().c_str()); - const int curMoney = PlayerInfo::getAttribute(PlayerInfo::MONEY); - if (v > curMoney) - { - if (localChatTab) - { - // TRANSLATORS: trade error - localChatTab->chatLog(_("You don't have enough money."), - BY_SERVER); - } - v = curMoney; - } - Net::getTradeHandler()->setMoney(v); - mMoneyField->setText(strprintf("%d", v)); - } -} - -void TradeWindow::close() -{ - Net::getTradeHandler()->cancel(); - clear(); -} - -void TradeWindow::clear() -{ - mAutoAddItem = nullptr; - mAutoAddToNick.clear(); - mAutoMoney = 0; - mAutoAddAmount = 0; - mGotMoney = 0; - mGotMaxMoney = 0; - mMoneyLabel->setForegroundColorAll(getThemeColor( - static_cast(Theme::LABEL)), getThemeColor( - static_cast(Theme::LABEL_OUTLINE))); -} - -void TradeWindow::addAutoItem(const std::string &nick, Item* const item, - const int amount) -{ - mAutoAddToNick = nick; - mAutoAddItem = item; - mAutoAddAmount = amount; -} - -void TradeWindow::addAutoMoney(const std::string &nick, const int money) -{ - mAutoAddToNick = nick; - mAutoMoney = money; -} - -void TradeWindow::initTrade(const std::string &nick) -{ - if (!player_node) - return; - - if (!mAutoAddToNick.empty() && mAutoAddToNick == nick) - { - if (mAutoAddItem && mAutoAddItem->getQuantity()) - { - const Inventory *const inv = PlayerInfo::getInventory(); - if (inv) - { - Item *const item = inv->findItem(mAutoAddItem->getId(), - mAutoAddItem->getColor()); - if (item) - tradeItem(item, mAutoAddItem->getQuantity()); - } - } - if (mAutoMoney) - { - Net::getTradeHandler()->setMoney(mAutoMoney); - mMoneyField->setText(strprintf("%d", mAutoMoney)); - } - } - clear(); - if (!player_relations.isGoodName(nick)) - setCaptionFont(gui->getSecureFont()); -} - -bool TradeWindow::checkItem(const Item *const item) const -{ - const int itemId = item->getId(); - if (PlayerInfo::isItemProtected(itemId)) - return false; - const Item *const tItem = mMyInventory->findItem( - itemId, item->getColor()); - - if (tItem && (tItem->getQuantity() > 1 - || item->getQuantity() > 1)) - { - if (localChatTab) - { - // TRANSLATORS: trade error - localChatTab->chatLog(_("Failed adding item. You can not " - "overlap one kind of item on the window."), BY_SERVER); - } - return false; - } - return true; -} - -bool TradeWindow::isInpupFocused() const -{ - return (mMoneyField && mMoneyField->isFocused()); -} diff --git a/src/gui/tradewindow.h b/src/gui/tradewindow.h deleted file mode 100644 index df6d8a80a..000000000 --- a/src/gui/tradewindow.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_TRADEWINDOW_H -#define GUI_TRADEWINDOW_H - -#include "gui/widgets/window.h" - -#include -#include - -#include - -class Button; -class Inventory; -class Item; -class ItemContainer; -class Label; -class TextField; - -/** - * Trade dialog. - * - * \ingroup Interface - */ -class TradeWindow final : public Window, - private gcn::ActionListener, - private gcn::SelectionListener -{ - public: - /** - * Constructor. - */ - TradeWindow(); - - A_DELETE_COPY(TradeWindow) - - /** - * Destructor. - */ - ~TradeWindow(); - - /** - * Displays expected money in the trade window. - */ - void setMoney(const int quantity); - - /** - * Add an item to the trade window. - */ - void addItem(const int id, const bool own, const int quantity, - const int refine, const unsigned char color) const; - - /** - * Reset both item containers - */ - void reset(); - - /** - * Add an item to the trade window. - */ - void addItem2(const int id, const bool own, const int quantity, - const int refine, const unsigned char color, - const bool equipment) const; - - /** - * Change quantity of an item. - */ - void changeQuantity(const int index, const bool own, - const int quantity) const; - - /** - * Increase quantity of an item. - */ - void increaseQuantity(const int index, const bool own, - const int quantity) const; - - /** - * Player received ok message from server - */ - void receivedOk(const bool own); - - /** - * Send trade packet. - */ - void tradeItem(const Item *const item, const int quantity, - const bool check = false) const; - - /** - * Updates the labels and makes sure only one item is selected in - * either my inventory or partner inventory. - */ - void valueChanged(const gcn::SelectionEvent &event) override; - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - /** - * Closes the Trade Window, as well as telling the server that the - * window has been closed. - */ - void close() override; - - /** - * Clear auto trade items. - */ - void clear(); - - /** - * Add item what will be added to trade. - */ - void addAutoItem(const std::string &nick, Item *const item, - const int amount); - - void addAutoMoney(const std::string &nick, const int money); - - void initTrade(const std::string &nick); - - std::string getAutoTradeNick() const A_WARN_UNUSED - { return mAutoAddToNick; } - - bool checkItem(const Item *const item) const A_WARN_UNUSED; - - bool isInpupFocused() const A_WARN_UNUSED; - - private: - enum Status - { - PREPARING = 0, /**< Players are adding items. (1) */ - PROPOSING, /**< Local player has confirmed the trade. (1) */ - ACCEPTING, /**< Accepting the trade. (2) */ - ACCEPTED /**< Local player has accepted the trade. */ - }; - - /** - * Sets the current status of the trade. - */ - void setStatus(const Status s); - - typedef const std::auto_ptr InventoryPtr; - InventoryPtr mMyInventory; - InventoryPtr mPartnerInventory; - - ItemContainer *mMyItemContainer; - ItemContainer *mPartnerItemContainer; - - Label *mMoneyLabel; - Button *mAddButton; - Button *mOkButton; - Button *mMoneyChangeButton; - TextField *mMoneyField; - - Status mStatus; - Item* mAutoAddItem; - std::string mAutoAddToNick; - int mGotMoney; - int mGotMaxMoney; - int mAutoMoney; - int mAutoAddAmount; - bool mOkOther; - bool mOkMe; -}; - -extern TradeWindow *tradeWindow; - -#endif // GUI_TRADEWINDOW_H diff --git a/src/gui/unregisterdialog.cpp b/src/gui/unregisterdialog.cpp deleted file mode 100644 index 3640456d0..000000000 --- a/src/gui/unregisterdialog.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/unregisterdialog.h" - -#include "client.h" - -#include "gui/okdialog.h" -#include "gui/registerdialog.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/label.h" -#include "gui/widgets/passwordfield.h" - -#include "net/logindata.h" -#include "net/loginhandler.h" -#include "net/net.h" - -#include "utils/gettext.h" - -#include -#include - -#include "debug.h" - -UnRegisterDialog::UnRegisterDialog(LoginData *const data) : - // TRANSLATORS: unregister dialog name - Window(_("Unregister"), true, nullptr, "unregister.xml"), - gcn::ActionListener(), - mLoginData(data), - mPasswordField(new PasswordField(this, mLoginData->password)), - // TRANSLATORS: unregister dialog. button. - mUnRegisterButton(new Button(this, _("Unregister"), "unregister", this)), - // TRANSLATORS: unregister dialog. button. - mCancelButton(new Button(this, _("Cancel"), "cancel", this)), - mWrongDataNoticeListener(new WrongDataNoticeListener) -{ - // TRANSLATORS: unregister dialog. label. - Label *const userLabel = new Label(this, strprintf(_("Name: %s"), - mLoginData->username.c_str())); - // TRANSLATORS: unregister dialog. label. - Label *const passwordLabel = new Label(this, _("Password:")); - - const int width = 210; - const int height = 80; - setContentSize(width, height); - - userLabel->setPosition(5, 5); - userLabel->setWidth(width - 5); - mPasswordField->setPosition( - 68, userLabel->getY() + userLabel->getHeight() + 7); - mPasswordField->setWidth(130); - - passwordLabel->setPosition(5, mPasswordField->getY() + 1); - - mCancelButton->setPosition( - width - 5 - mCancelButton->getWidth(), - height - 5 - mCancelButton->getHeight()); - mUnRegisterButton->setPosition( - mCancelButton->getX() - 5 - mUnRegisterButton->getWidth(), - mCancelButton->getY()); - - add(userLabel); - add(passwordLabel); - add(mPasswordField); - add(mUnRegisterButton); - add(mCancelButton); - - center(); - setVisible(true); - mPasswordField->requestFocus(); - mPasswordField->setActionEventId("cancel"); -} - -UnRegisterDialog::~UnRegisterDialog() -{ - delete mWrongDataNoticeListener; - mWrongDataNoticeListener = nullptr; -} - -void UnRegisterDialog::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "cancel") - { - client->setState(STATE_CHAR_SELECT); - } - else if (eventId == "unregister") - { - const std::string username = mLoginData->username.c_str(); - const std::string password = mPasswordField->getText(); - logger->log("UnregisterDialog::unregistered, Username is %s", - username.c_str()); - - std::stringstream errorMsg; - bool error = false; - - const unsigned int min = Net::getLoginHandler() - ->getMinPasswordLength(); - const unsigned int max = Net::getLoginHandler() - ->getMaxPasswordLength(); - - if (password.length() < min) - { - // TRANSLATORS: unregister dialog. error message. - errorMsg << strprintf(_("The password needs to be at least %u " - "characters long."), min); - error = true; - } - else if (password.length() > max) - { - // TRANSLATORS: unregister dialog. error message. - errorMsg << strprintf(_("The password needs to be less than " - "%u characters long."), max); - error = true; - } - - if (error) - { - mWrongDataNoticeListener->setTarget(this->mPasswordField); - - // TRANSLATORS: unregister dialog. error message. - OkDialog *const dlg = new OkDialog(_("Error"), - errorMsg.str(), DIALOG_ERROR); - dlg->addActionListener(mWrongDataNoticeListener); - } - else - { - // No errors detected, unregister the new user. - mUnRegisterButton->setEnabled(false); - mLoginData->password = password; - client->setState(STATE_UNREGISTER_ATTEMPT); - } - } -} diff --git a/src/gui/unregisterdialog.h b/src/gui/unregisterdialog.h deleted file mode 100644 index de0da27bb..000000000 --- a/src/gui/unregisterdialog.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_UNREGISTERDIALOG_H -#define GUI_UNREGISTERDIALOG_H - -#include "gui/widgets/window.h" - -#include - -class Button; -class LoginData; -class TextField; -class WrongDataNoticeListener; - -/** - * The Unregister dialog. - * - * \ingroup Interface - */ -class UnRegisterDialog final : public Window, public gcn::ActionListener -{ - public: - /** - * Constructor - * - * @see Window::Window - */ - explicit UnRegisterDialog(LoginData *const loginData); - - A_DELETE_COPY(UnRegisterDialog) - - ~UnRegisterDialog(); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - private: - LoginData *mLoginData; - - TextField *mPasswordField; - - Button *mUnRegisterButton; - Button *mCancelButton; - - WrongDataNoticeListener *mWrongDataNoticeListener; -}; - -#endif // GUI_UNREGISTERDIALOG_H diff --git a/src/gui/updaterwindow.cpp b/src/gui/updaterwindow.cpp deleted file mode 100644 index 7eda825ad..000000000 --- a/src/gui/updaterwindow.cpp +++ /dev/null @@ -1,943 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/updaterwindow.h" - -#include "client.h" -#include "configuration.h" - -#include "input/keydata.h" -#include "input/keyevent.h" - -#include "gui/widgets/browserbox.h" -#include "gui/widgets/button.h" -#include "gui/widgets/label.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/progressbar.h" -#include "gui/widgets/scrollarea.h" - -#include "net/logindata.h" - -#include "resources/resourcemanager.h" - -#include "utils/gettext.h" -#include "utils/mkdir.h" -#include "utils/paths.h" -#include "utils/process.h" - -#include - -#include - -#include "debug.h" - -const std::string xmlUpdateFile("resources.xml"); -const std::string txtUpdateFile("resources2.txt"); -const std::string updateServer2 - ("http://download.evolonline.org/manaplus/updates/"); - -/** - * Load the given file into a vector of updateFiles. - */ -static std::vector loadXMLFile(const std::string &fileName) -{ - std::vector files; - XML::Document doc(fileName, false); - const XmlNodePtr rootNode = doc.rootNode(); - - if (!rootNode || !xmlNameEqual(rootNode, "updates")) - { - logger->log("Error loading update file: %s", fileName.c_str()); - return files; - } - - for_each_xml_child_node(fileNode, rootNode) - { - if (!xmlNameEqual(fileNode, "update")) - continue; - - if (XML::getProperty(fileNode, "group", "default") != "default") - continue; - - UpdateFile file; - file.name = XML::getProperty(fileNode, "file", ""); - file.hash = XML::getProperty(fileNode, "hash", ""); - file.type = XML::getProperty(fileNode, "type", "data"); - file.desc = XML::getProperty(fileNode, "description", ""); - const std::string version = XML::getProperty( - fileNode, "version", ""); - if (!version.empty()) - { - if (version > CHECK_VERSION) - continue; - } - const std::string notVersion = XML::getProperty( - fileNode, "notVersion", ""); - if (!notVersion.empty()) - { - if (notVersion <= CHECK_VERSION) - continue; - } - if (XML::getProperty(fileNode, "required", "yes") == "yes") - file.required = true; - else - file.required = false; - - if (checkPath(file.name)) - files.push_back(file); - } - - return files; -} - -static std::vector loadTxtFile(const std::string &fileName) -{ - std::vector files; - std::ifstream fileHandler; - fileHandler.open(fileName.c_str(), std::ios::in); - - if (fileHandler.is_open()) - { - while (fileHandler.good()) - { - char name[256]; - char hash[50]; - fileHandler.getline(name, 256, ' '); - fileHandler.getline(hash, 50); - - UpdateFile thisFile; - thisFile.name = name; - thisFile.hash = hash; - thisFile.type = "data"; - thisFile.required = true; - thisFile.desc.clear(); - - if (!thisFile.name.empty() && checkPath(thisFile.name)) - files.push_back(thisFile); - } - } - else - { - logger->log("Error loading update file: %s", fileName.c_str()); - } - fileHandler.close(); - - return files; -} - -UpdaterWindow::UpdaterWindow(const std::string &updateHost, - const std::string &updatesDir, - const bool applyUpdates, - const int updateType): - // TRANSLATORS: updater window name - Window(_("Updating..."), false, nullptr, "update.xml"), - gcn::ActionListener(), - gcn::KeyListener(), - mDownloadStatus(UPDATE_NEWS), - mUpdateHost(updateHost), - mUpdatesDir(updatesDir), - mUpdatesDirReal(updatesDir), - mCurrentFile("news.txt"), - mNewLabelCaption(), - mDownloadProgress(0.0F), - mDownloadMutex(), - mCurrentChecksum(0), - mStoreInMemory(true), - mDownloadComplete(true), - mUserCancel(false), - mDownloadedBytes(0), - mMemoryBuffer(nullptr), - mDownload(nullptr), - mUpdateFiles(), - mTempUpdateFiles(), - mUpdateIndex(0), - mUpdateIndexOffset(0), - mLoadUpdates(applyUpdates), - mUpdateType(updateType), - // TRANSLATORS: updater window label - mLabel(new Label(this, _("Connecting..."))), - // TRANSLATORS: updater window button - mCancelButton(new Button(this, _("Cancel"), "cancel", this)), - // TRANSLATORS: updater window button - mPlayButton(new Button(this, _("Play"), "play", this)), - mProgressBar(new ProgressBar(this, 0.0, 310, 0)), - mBrowserBox(new BrowserBox(this)), - mScrollArea(new ScrollArea(mBrowserBox, true, "update_background.xml")), - mUpdateServerPath(mUpdateHost) -{ - setWindowName("UpdaterWindow"); - setResizable(true); - setDefaultSize(450, 400, ImageRect::CENTER); - setMinWidth(310); - setMinHeight(220); - - mProgressBar->setSmoothProgress(false); - mBrowserBox->setOpaque(false); - mBrowserBox->setLinkHandler(this); - mBrowserBox->setEnableKeys(true); - mBrowserBox->setEnableTabs(true); - mPlayButton->setEnabled(false); - - ContainerPlacer placer; - placer = getPlacer(0, 0); - - placer(0, 0, mScrollArea, 5, 3).setPadding(3); - placer(0, 3, mLabel, 5); - placer(0, 4, mProgressBar, 5); - placer(3, 5, mCancelButton); - placer(4, 5, mPlayButton); - - Layout &layout = getLayout(); - layout.setRowHeight(0, Layout::AUTO_SET); - - addKeyListener(this); - - loadWindowState(); - setVisible(true); - mCancelButton->requestFocus(); - removeProtocol(mUpdateServerPath); - - download(); -} - -UpdaterWindow::~UpdaterWindow() -{ - if (mLoadUpdates) - loadUpdates(); - - if (mDownload) - { - mDownload->cancel(); - - delete mDownload; - mDownload = nullptr; - } - free(mMemoryBuffer); -} - -void UpdaterWindow::setProgress(const float p) -{ - // Do delayed progress bar update, since Guichan isn't thread-safe - MutexLocker lock(&mDownloadMutex); - mDownloadProgress = p; -} - -void UpdaterWindow::setLabel(const std::string &str) -{ - // Do delayed label text update, since Guichan isn't thread-safe - MutexLocker lock(&mDownloadMutex); - mNewLabelCaption = str; -} - -void UpdaterWindow::enable() -{ - mCancelButton->setEnabled(false); - mPlayButton->setEnabled(true); - mPlayButton->requestFocus(); - - if (mUpdateType & LoginData::Upd_Close) - client->setState(STATE_LOAD_DATA); -} - -void UpdaterWindow::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "cancel") - { - // Register the user cancel - mUserCancel = true; - // Skip the updating process - if (mDownloadStatus != UPDATE_COMPLETE) - { - mDownload->cancel(); - mDownloadStatus = UPDATE_ERROR; - } - } - else if (eventId == "play") - { - client->setState(STATE_LOAD_DATA); - } -} - -void UpdaterWindow::keyPressed(gcn::KeyEvent &keyEvent) -{ - const int actionId = static_cast(&keyEvent)->getActionId(); - if (actionId == static_cast(Input::KEY_GUI_CANCEL)) - { - action(gcn::ActionEvent(nullptr, mCancelButton->getActionEventId())); - client->setState(STATE_LOGIN); - } - else if (actionId == static_cast(Input::KEY_GUI_SELECT) - || actionId == static_cast(Input::KEY_GUI_SELECT2)) - { - if (mDownloadStatus == UPDATE_COMPLETE || - mDownloadStatus == UPDATE_ERROR) - { - action(gcn::ActionEvent(nullptr, mPlayButton->getActionEventId())); - } - else - { - action(gcn::ActionEvent(nullptr, - mCancelButton->getActionEventId())); - } - } -} - -void UpdaterWindow::loadNews() -{ - if (!mMemoryBuffer) - { - logger->log1("Couldn't load news"); - return; - } - - // Reallocate and include terminating 0 character - mMemoryBuffer = static_cast(realloc( - mMemoryBuffer, mDownloadedBytes + 1)); - - mMemoryBuffer[mDownloadedBytes] = '\0'; - mBrowserBox->clearRows(); - - std::string newsName = mUpdatesDir + "/local/help/news.txt"; - mkdir_r((mUpdatesDir + "/local/help/").c_str()); - bool firstLine(true); - std::ofstream file; - std::stringstream ss(mMemoryBuffer); - std::string line; - file.open(newsName.c_str(), std::ios::out); - while (std::getline(ss, line, '\n')) - { - if (firstLine) - { - firstLine = false; - const size_t i = line.find("##9 Latest client version: ##6"); - if (!i) - continue; - - if (file.is_open()) - file << line << std::endl; - mBrowserBox->addRow(line); - } - else - { - if (file.is_open()) - file << line << std::endl; - mBrowserBox->addRow(line); - } - } - - file.close(); - // Free the memory buffer now that we don't need it anymore - free(mMemoryBuffer); - mMemoryBuffer = nullptr; - mDownloadedBytes = 0; - - mScrollArea->setVerticalScrollAmount(0); -} - -void UpdaterWindow::loadPatch() -{ - if (!mMemoryBuffer) - { - logger->log1("Couldn't load patch"); - return; - } - - // Reallocate and include terminating 0 character - mMemoryBuffer = static_cast( - realloc(mMemoryBuffer, mDownloadedBytes + 1)); - mMemoryBuffer[mDownloadedBytes] = '\0'; - - std::string version; - - // Tokenize and add each line separately - char *line = strtok(mMemoryBuffer, "\n"); - if (line) - { - version = line; - if (serverVersion < 1) - { - line = strtok(nullptr, "\n"); - if (line) - { - mBrowserBox->addRow(strprintf("##9 Latest client version: " - "##6ManaPlus %s##0", line), true); - } - } - if (version > CHECK_VERSION) - { -#if defined(ANDROID) - mBrowserBox->addRow("", true); - mBrowserBox->addRow("##1You can download from [[@@" - "https://play.google.com/store/apps/details?id=org.evolonline" - ".beta.manaplus|Google Play@@]", true); - mBrowserBox->addRow("##1ManaPlus updated.", true); -#elif defined(WIN32) - mBrowserBox->addRow("", true); - mBrowserBox->addRow(" ##1[@@http://download.evolonline.org/" - "manaplus/download/manaplus-win32.exe|download here@@]", true); -#else - mBrowserBox->addRow("", true); - mBrowserBox->addRow(" ##1@@http://manaplus.org/|" - "http://manaplus.org/@@", true); - mBrowserBox->addRow("##1You can download it from", true); - mBrowserBox->addRow("##1ManaPlus updated.", true); -#endif - } - else - { - mBrowserBox->addRow("You have latest client version.", true); - } - } - - // Free the memory buffer now that we don't need it anymore - free(mMemoryBuffer); - mMemoryBuffer = nullptr; - mDownloadedBytes = 0; - - mScrollArea->setVerticalScrollAmount(0); -} - -int UpdaterWindow::updateProgress(void *ptr, DownloadStatus status, - size_t dt, size_t dn) -{ - UpdaterWindow *const uw = reinterpret_cast(ptr); - if (!uw) - return -1; - - if (status == DOWNLOAD_STATUS_COMPLETE) - { - uw->mDownloadComplete = true; - } - else if (status == DOWNLOAD_STATUS_ERROR || - status == DOWNLOAD_STATUS_CANCELLED) - { - if (uw->mDownloadStatus == UPDATE_COMPLETE) - { // ignoring error in last state (was UPDATE_PATCH) - uw->mDownloadStatus = UPDATE_COMPLETE; - uw->mDownloadComplete = true; - free(uw->mMemoryBuffer); - uw->mMemoryBuffer = nullptr; - } - else - { - uw->mDownloadStatus = UPDATE_ERROR; - } - } - - if (!dt) - dt = 1; - - float progress = static_cast(dn) / - static_cast(dt); - - if (progress != progress) - progress = 0.0F; // check for NaN - if (progress < 0.0F) - progress = 0.0F; // no idea how this could ever happen, - // but why not check for it anyway. - if (progress > 1.0F) - progress = 1.0F; - - uw->setLabel(std::string(uw->mCurrentFile).append(" (") - .append(toString(static_cast(progress * 100))).append("%)")); - - uw->setProgress(progress); - - if (client->getState() != STATE_UPDATE - || uw->mDownloadStatus == UPDATE_ERROR) - { - // If the action was canceled return an error code to stop the mThread - return -1; - } - - return 0; -} - -size_t UpdaterWindow::memoryWrite(void *ptr, size_t size, - size_t nmemb, void *stream) -{ - UpdaterWindow *const uw = reinterpret_cast(stream); - const size_t totalMem = size * nmemb; - uw->mMemoryBuffer = static_cast(realloc(uw->mMemoryBuffer, - uw->mDownloadedBytes + totalMem)); - if (uw->mMemoryBuffer) - { - memcpy(&(uw->mMemoryBuffer[uw->mDownloadedBytes]), ptr, totalMem); - uw->mDownloadedBytes += static_cast(totalMem); - } - - return totalMem; -} - -void UpdaterWindow::download() -{ - if (mDownload) - { - mDownload->cancel(); - delete mDownload; - } - if (mDownloadStatus == UPDATE_PATCH) - { - mDownload = new Net::Download(this, - "http://manaplus.org/update/" + mCurrentFile, - updateProgress, true); - } - else - { - mDownload = new Net::Download(this, std::string(mUpdateHost).append( - "/").append(mCurrentFile), updateProgress); - } - - if (mStoreInMemory) - { - mDownload->setWriteFunction(UpdaterWindow::memoryWrite); - } - else - { - if (mDownloadStatus == UPDATE_RESOURCES) - { - mDownload->setFile(std::string(mUpdatesDir).append("/").append( - mCurrentFile), mCurrentChecksum); - } - else - { - mDownload->setFile(std::string(mUpdatesDir).append( - "/").append(mCurrentFile)); - } - } - - if (mDownloadStatus != UPDATE_RESOURCES) - mDownload->noCache(); - - setLabel(mCurrentFile + " (0%)"); - mDownloadComplete = false; - - mDownload->start(); -} - -void UpdaterWindow::loadUpdates() -{ - const ResourceManager *const resman = ResourceManager::getInstance(); - if (mUpdateFiles.empty()) - { // updates not downloaded - mUpdateFiles = loadXMLFile(std::string(mUpdatesDir).append( - "/").append(xmlUpdateFile)); - if (mUpdateFiles.empty()) - { - logger->log("Warning this server does not have a" - " %s file falling back to %s", xmlUpdateFile.c_str(), - txtUpdateFile.c_str()); - mUpdateFiles = loadTxtFile(std::string(mUpdatesDir).append( - "/").append(txtUpdateFile)); - } - } - - std::string fixPath = mUpdatesDir + "/fix"; - const unsigned sz = static_cast(mUpdateFiles.size()); - for (mUpdateIndex = 0; mUpdateIndex < sz; mUpdateIndex++) - { - UpdaterWindow::addUpdateFile(resman, mUpdatesDir, fixPath, - mUpdateFiles[mUpdateIndex].name, false); - } - loadManaPlusUpdates(mUpdatesDir, resman); -} - -void UpdaterWindow::loadLocalUpdates(const std::string &dir) -{ - const ResourceManager *const resman = ResourceManager::getInstance(); - - std::vector updateFiles - = loadXMLFile(std::string(dir).append("/").append(xmlUpdateFile)); - - if (updateFiles.empty()) - { - logger->log("Warning this server does not have a" - " %s file falling back to %s", xmlUpdateFile.c_str(), - txtUpdateFile.c_str()); - updateFiles = loadTxtFile(std::string(dir).append( - "/").append(txtUpdateFile)); - } - - const std::string fixPath = dir + "/fix"; - for (unsigned int updateIndex = 0, sz = static_cast( - updateFiles.size()); updateIndex < sz; updateIndex ++) - { - UpdaterWindow::addUpdateFile(resman, dir, fixPath, - updateFiles[updateIndex].name, false); - } - loadManaPlusUpdates(dir, resman); -} - -void UpdaterWindow::unloadUpdates(const std::string &dir) -{ - const ResourceManager *const resman = ResourceManager::getInstance(); - std::vector updateFiles - = loadXMLFile(std::string(dir).append("/").append(xmlUpdateFile)); - - if (updateFiles.empty()) - { - updateFiles = loadTxtFile(std::string(dir).append( - "/").append(txtUpdateFile)); - } - - const std::string fixPath = dir + "/fix"; - for (unsigned int updateIndex = 0, sz = static_cast( - updateFiles.size()); updateIndex < sz; updateIndex ++) - { - UpdaterWindow::removeUpdateFile(resman, dir, fixPath, - updateFiles[updateIndex].name); - } - unloadManaPlusUpdates(dir, resman); -} - -void UpdaterWindow::loadManaPlusUpdates(const std::string &dir, - const ResourceManager *const resman) -{ - std::string fixPath = dir + "/fix"; - std::vector updateFiles - = loadXMLFile(std::string(fixPath).append("/").append(xmlUpdateFile)); - - for (unsigned int updateIndex = 0, sz = static_cast( - updateFiles.size()); updateIndex < sz; updateIndex ++) - { - std::string name = updateFiles[updateIndex].name; - if (strStartWith(name, "manaplus_")) - { - struct stat statbuf; - std::string file = std::string(fixPath).append("/").append(name); - if (!stat(file.c_str(), &statbuf)) - resman->addToSearchPath(file, false); - } - } -} - -void UpdaterWindow::unloadManaPlusUpdates(const std::string &dir, - const ResourceManager *const resman) -{ - const std::string fixPath = dir + "/fix"; - const std::vector updateFiles - = loadXMLFile(std::string(fixPath).append("/").append(xmlUpdateFile)); - - for (unsigned int updateIndex = 0, sz = static_cast( - updateFiles.size()); updateIndex < sz; updateIndex ++) - { - std::string name = updateFiles[updateIndex].name; - if (strStartWith(name, "manaplus_")) - { - struct stat statbuf; - const std::string file = std::string( - fixPath).append("/").append(name); - if (!stat(file.c_str(), &statbuf)) - resman->removeFromSearchPath(file); - } - } -} - -void UpdaterWindow::addUpdateFile(const ResourceManager *const resman, - const std::string &path, - const std::string &fixPath, - const std::string &file, - const bool append) -{ - const std::string tmpPath = std::string(path).append("/").append(file); - if (!append) - resman->addToSearchPath(tmpPath, append); - - const std::string fixFile = std::string(fixPath).append("/").append(file); - struct stat statbuf; - if (!stat(fixFile.c_str(), &statbuf)) - resman->addToSearchPath(fixFile, append); - - if (append) - resman->addToSearchPath(tmpPath, append); -} - -void UpdaterWindow::removeUpdateFile(const ResourceManager *const resman, - const std::string &path, - const std::string &fixPath, - const std::string &file) -{ - resman->removeFromSearchPath(std::string(path).append("/").append(file)); - const std::string fixFile = std::string(fixPath).append("/").append(file); - struct stat statbuf; - if (!stat(fixFile.c_str(), &statbuf)) - resman->removeFromSearchPath(fixFile); -} - -void UpdaterWindow::logic() -{ - BLOCK_START("UpdaterWindow::logic") - // Update Scroll logic - mScrollArea->logic(); - - // Synchronize label caption when necessary - { - MutexLocker lock(&mDownloadMutex); - - if (mLabel->getCaption() != mNewLabelCaption) - { - mLabel->setCaption(mNewLabelCaption); - mLabel->adjustSize(); - } - - mProgressBar->setProgress(mDownloadProgress); - if (mUpdateFiles.size() && mUpdateIndex <= mUpdateFiles.size()) - { - mProgressBar->setText(strprintf("%u/%u", mUpdateIndex - + mUpdateIndexOffset + 1, static_cast( - mUpdateFiles.size()) + static_cast( - mTempUpdateFiles.size()) + 1)); - } - else - { - mProgressBar->setText(""); - } - } - - switch (mDownloadStatus) - { - case UPDATE_ERROR: - mBrowserBox->addRow(""); - // TRANSLATORS: update message - mBrowserBox->addRow(_("##1 The update process is incomplete.")); - // TRANSLATORS: Continues "The update process is incomplete.". - mBrowserBox->addRow(_("##1 It is strongly recommended that")); - // TRANSLATORS: Begins "It is strongly recommended that". - mBrowserBox->addRow(_("##1 you try again later.")); - - mBrowserBox->addRow(mDownload->getError()); - mScrollArea->setVerticalScrollAmount( - mScrollArea->getVerticalMaxScroll()); - mDownloadStatus = UPDATE_COMPLETE; - break; - case UPDATE_NEWS: - if (mDownloadComplete) - { - // Parse current memory buffer as news and dispose of the data - loadNews(); - - mCurrentFile = xmlUpdateFile; - mStoreInMemory = false; - mDownloadStatus = UPDATE_LIST; - download(); // download() changes mDownloadComplete to false - } - break; - case UPDATE_PATCH: - if (mDownloadComplete) - { - // Parse current memory buffer as news and dispose of the data - loadPatch(); - - mUpdateHost = updateServer2 + mUpdateServerPath; - mUpdatesDir.append("/fix"); - mCurrentFile = xmlUpdateFile; - mStoreInMemory = false; - mDownloadStatus = UPDATE_LIST2; - download(); - } - break; - - case UPDATE_LIST: - if (mDownloadComplete) - { - if (mCurrentFile == xmlUpdateFile) - { - mUpdateFiles = loadXMLFile(std::string(mUpdatesDir).append( - "/").append(xmlUpdateFile)); - - if (mUpdateFiles.empty()) - { - logger->log("Warning this server does not have a %s" - " file falling back to %s", - xmlUpdateFile.c_str(), - txtUpdateFile.c_str()); - - // If the resources.xml file fails, - // fall back onto a older version - mCurrentFile = txtUpdateFile; - mStoreInMemory = false; - mDownloadStatus = UPDATE_LIST; - download(); - break; - } - } - else if (mCurrentFile == txtUpdateFile) - { - mUpdateFiles = loadTxtFile(std::string(mUpdatesDir).append( - "/").append(txtUpdateFile)); - } - mStoreInMemory = false; - mDownloadStatus = UPDATE_RESOURCES; - } - break; - case UPDATE_RESOURCES: - if (mDownloadComplete) - { - if (mUpdateIndex < mUpdateFiles.size()) - { - UpdateFile thisFile = mUpdateFiles[mUpdateIndex]; - if (!thisFile.required) - { - // This statement checks to see if the file type - // is music, and if download-music is true - // If it fails, this statement returns true, - // and results in not downloading the file - // Else it will ignore the break, - // and download the file. - - if (!(thisFile.type == "music" - && config.getBoolValue("download-music"))) - { - mUpdateIndex++; - break; - } - } - mCurrentFile = thisFile.name; - std::string checksum; - checksum = thisFile.hash; - std::stringstream ss(checksum); - ss >> std::hex >> mCurrentChecksum; - - std::ifstream temp((std::string(mUpdatesDir).append( - "/").append(mCurrentFile)).c_str()); - - if (!temp.is_open() || !validateFile(std::string( - mUpdatesDir).append("/").append(mCurrentFile), - mCurrentChecksum)) - { - temp.close(); - download(); - } - else - { - temp.close(); - logger->log("%s already here", mCurrentFile.c_str()); - } - mUpdateIndex++; - } - else - { - // Download of updates completed - mCurrentFile = "latest.txt"; - mStoreInMemory = true; - mDownloadStatus = UPDATE_PATCH; - download(); // download() changes - // mDownloadComplete to false - } - } - break; - case UPDATE_LIST2: - if (mDownloadComplete) - { - if (mCurrentFile == xmlUpdateFile) - { - mTempUpdateFiles = loadXMLFile(std::string( - mUpdatesDir).append("/").append(xmlUpdateFile)); - } - mUpdateIndexOffset = mUpdateIndex; - mUpdateIndex = 0; - mStoreInMemory = false; - mDownloadStatus = UPDATE_RESOURCES2; - download(); - } - break; - case UPDATE_RESOURCES2: - if (mDownloadComplete) - { - if (mUpdateIndex < mTempUpdateFiles.size()) - { - const UpdateFile thisFile = mTempUpdateFiles[mUpdateIndex]; - mCurrentFile = thisFile.name; - std::string checksum; - checksum = thisFile.hash; - std::stringstream ss(checksum); - ss >> std::hex >> mCurrentChecksum; - - std::ifstream temp((std::string(mUpdatesDir).append( - "/").append(mCurrentFile)).c_str()); - - if (!temp.is_open() || !validateFile(std::string( - mUpdatesDir).append("/").append(mCurrentFile), - mCurrentChecksum)) - { - temp.close(); - download(); - } - else - { - temp.close(); - logger->log("%s already here", mCurrentFile.c_str()); - } - mUpdateIndex++; - } - else - { - mUpdatesDir = mUpdatesDirReal; - mDownloadStatus = UPDATE_COMPLETE; - } - } - break; - case UPDATE_COMPLETE: - mUpdatesDir = mUpdatesDirReal; - enable(); - // TRANSLATORS: updater window label - setLabel(_("Completed")); - break; - case UPDATE_IDLE: - break; - default: - logger->log("UpdaterWindow::logic unknown status: " - + toString(static_cast(mDownloadStatus))); - break; - } - BLOCK_END("UpdaterWindow::logic") -} - -bool UpdaterWindow::validateFile(const std::string &filePath, - const unsigned long hash) -{ - FILE *const file = fopen(filePath.c_str(), "rb"); - if (!file) - return false; - - const unsigned long adler = Net::Download::fadler32(file); - fclose(file); - return adler == hash; -} - -unsigned long UpdaterWindow::getFileHash(const std::string &filePath) -{ - int size = 0; - char *const buf = static_cast(ResourceManager::loadFile( - filePath, size)); - if (!buf) - return 0; - return Net::Download::adlerBuffer(buf, size); -} - -void UpdaterWindow::handleLink(const std::string &link, - gcn::MouseEvent *event A_UNUSED) -{ - if (strStartWith(link, "http://") || strStartWith(link, "https://")) - openBrowser(link); -} diff --git a/src/gui/updaterwindow.h b/src/gui/updaterwindow.h deleted file mode 100644 index e317e3f95..000000000 --- a/src/gui/updaterwindow.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_UPDATERWINDOW_H -#define GUI_UPDATERWINDOW_H - -#include "gui/widgets/linkhandler.h" -#include "gui/widgets/window.h" - -#include "net/download.h" - -#include "utils/mutex.h" - -#include -#include - -#include -#include - -class BrowserBox; -class Button; -class Label; -class ProgressBar; -class ResourceManager; -class ScrollArea; - -struct UpdateFile final -{ - public: - UpdateFile() : - name(), - hash(), - type(), - desc(), - required(false) - { - } - std::string name; - std::string hash; - std::string type; - std::string desc; - bool required; -}; - -/** - * Update progress window GUI - * - * \ingroup GUI - */ -class UpdaterWindow final : public Window, - public gcn::ActionListener, - public LinkHandler, - public gcn::KeyListener -{ - public: - /** - * Constructor. - * - * @param updateHost Host where to get the updated files. - * @param updatesDir Directory where to store updates (should be absolute - * and already created). - * @param applyUpdates If true, the update window will pass the updates to teh - * resource manager - */ - UpdaterWindow(const std::string &updateHost, - const std::string &updatesDir, - const bool applyUpdates, const int updateType); - - A_DELETE_COPY(UpdaterWindow) - - /** - * Destructor - */ - ~UpdaterWindow(); - - /** - * Set's progress bar status - */ - void setProgress(const float p); - - /** - * Set's label above progress - */ - void setLabel(const std::string &); - - /** - * Enables play button - */ - void enable(); - - /** - * Loads and display news. Assumes the news file contents have been loaded - * into the memory buffer. - */ - void loadNews(); - - void loadPatch(); - - void action(const gcn::ActionEvent &event) override; - - void keyPressed(gcn::KeyEvent &keyEvent) override; - - void logic() override; - - void handleLink(const std::string &link, - gcn::MouseEvent *event A_UNUSED) override; - - static void loadLocalUpdates(const std::string &dir); - - static void unloadUpdates(const std::string &dir); - - static void addUpdateFile(const ResourceManager *const resman, - const std::string &path, - const std::string &fixPath, - const std::string &file, - const bool append); - - static void removeUpdateFile(const ResourceManager *const resman, - const std::string &path, - const std::string &fixPath, - const std::string &file); - - static void loadManaPlusUpdates(const std::string &dir, - const ResourceManager *const resman); - - static void unloadManaPlusUpdates(const std::string &dir, - const ResourceManager *const resman); - - static unsigned long getFileHash(const std::string &filePath); - -private: - void download(); - - /** - * Loads the updates this window has gotten into the resource manager - */ - void loadUpdates(); - - - /** - * A download callback for progress updates. - */ - static int updateProgress(void *ptr, DownloadStatus status, - size_t dt, size_t dn); - - /** - * A libcurl callback for writing to memory. - */ - static size_t memoryWrite(void *ptr, size_t size, size_t nmemb, - void *stream); - - static bool validateFile(const std::string &filePath, - const unsigned long hash) A_WARN_UNUSED; - - enum UpdateDownloadStatus - { - UPDATE_ERROR = 0, - UPDATE_IDLE, - UPDATE_LIST, - UPDATE_COMPLETE, - UPDATE_NEWS, - UPDATE_RESOURCES, - UPDATE_PATCH, - UPDATE_LIST2, - UPDATE_RESOURCES2 - }; - - /** Status of the current download. */ - UpdateDownloadStatus mDownloadStatus; - - /** Host where we get the updated files. */ - std::string mUpdateHost; - - /** Place where the updates are stored (absolute path). */ - std::string mUpdatesDir; - - std::string mUpdatesDirReal; - - /** The file currently downloading. */ - std::string mCurrentFile; - - /** The new label caption to be set in the logic method. */ - std::string mNewLabelCaption; - - /** The new progress value to be set in the logic method. */ - float mDownloadProgress; - - // The mutex used to guard access to mNewLabelCaption - // and mDownloadProgress. - Mutex mDownloadMutex; - - /** The Adler32 checksum of the file currently downloading. */ - unsigned long mCurrentChecksum; - - /** A flag to indicate whether to use a memory buffer or a regular file. */ - bool mStoreInMemory; - - /** Flag that show if current download is complete. */ - bool mDownloadComplete; - - /** Flag that show if the user has canceled the update. */ - bool mUserCancel; - - /** Byte count currently downloaded in mMemoryBuffer. */ - int mDownloadedBytes; - - /** Buffer for files downloaded to memory. */ - char *mMemoryBuffer; - - /** Download handle. */ - Net::Download *mDownload; - - /** List of files to download. */ - std::vector mUpdateFiles; - - /** List of temp files to download. */ - std::vector mTempUpdateFiles; - - /** Index of the file to be downloaded. */ - unsigned int mUpdateIndex; - - /** Index offset for disaplay downloaded file. */ - unsigned int mUpdateIndexOffset; - - /** Tells ~UpdaterWindow() if it should load updates */ - bool mLoadUpdates; - - int mUpdateType; - - Label *mLabel; /**< Progress bar caption. */ - Button *mCancelButton; /**< Button to stop the update process. */ - Button *mPlayButton; /**< Button to start playing. */ - ProgressBar *mProgressBar; /**< Update progress bar. */ - BrowserBox *mBrowserBox; /**< Box to display news. */ - ScrollArea *mScrollArea; /**< Used to scroll news box. */ - std::string mUpdateServerPath; -}; - -#endif // GUI_UPDATERWINDOW_H diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index 61b5f5f6d..1aa5e1d9b 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -36,10 +36,11 @@ #include "gui/beingpopup.h" #include "gui/gui.h" -#include "gui/ministatuswindow.h" #include "gui/popupmenu.h" #include "gui/textpopup.h" +#include "gui/windows/ministatuswindow.h" + #include #include "debug.h" diff --git a/src/gui/whoisonline.cpp b/src/gui/whoisonline.cpp deleted file mode 100644 index 4fd630a46..000000000 --- a/src/gui/whoisonline.cpp +++ /dev/null @@ -1,865 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 Andrei Karas - * Copyright (C) 2011-2013 The ManaPlus developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/whoisonline.h" - -#include "guild.h" -#include "party.h" - -#include "gui/chatwindow.h" -#include "gui/socialwindow.h" -#include "gui/viewport.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/browserbox.h" -#include "gui/widgets/scrollarea.h" - -#include "actorspritemanager.h" -#include "client.h" -#include "configuration.h" -#include "main.h" - -#include "being/localplayer.h" -#include "being/playerrelations.h" - -#include "net/download.h" -#include "net/net.h" -#include "net/playerhandler.h" - -#include "utils/gettext.h" -#include "utils/sdlhelper.h" - -#include -#include -#include - -// Curl should be included after Guichan to avoid Windows redefinitions -#include - -#include "debug.h" - -#ifdef free -#undef free -#endif - -#ifdef malloc -#undef malloc -#endif - -class NameFunctuator final -{ - public: - bool operator()(const OnlinePlayer *left, - const OnlinePlayer *right) const - { - return (compareStrI(left->getNick(), right->getNick()) < 0); - } -} nameCompare; - -WhoIsOnline::WhoIsOnline() : - // TRANSLATORS: who is online window name - Window(_("Who Is Online - Updating"), false, nullptr, "whoisonline.xml"), - mThread(nullptr), - mDownloadStatus(UPDATE_LIST), - mDownloadComplete(true), - mDownloadedBytes(0), - mMemoryBuffer(nullptr), - mCurlError(new char[CURL_ERROR_SIZE]), - mBrowserBox(new BrowserBox(this)), - mScrollArea(new ScrollArea(mBrowserBox, false)), - mUpdateTimer(0), - mOnlinePlayers(), - mOnlineNicks(), - // TRANSLATORS: who is online. button. - mUpdateButton(new Button(this, _("Update"), "update", this)), - mAllowUpdate(true), - mShowLevel(false), - mUpdateOnlineList(config.getBoolValue("updateOnlineList")), - - mGroupFriends(true) -{ - mCurlError[0] = 0; - setWindowName("WhoIsOnline"); - - const int h = 350; - const int w = 200; - setDefaultSize(w, h, ImageRect::CENTER); - setVisible(false); - setCloseButton(true); - setResizable(true); - setStickyButtonLock(true); - setSaveVisible(true); - - mUpdateButton->setEnabled(false); - mUpdateButton->setDimension(gcn::Rectangle(5, 5, w - 10, 20 + 5)); - - mBrowserBox->setOpaque(false); - mBrowserBox->setHighlightMode(BrowserBox::BACKGROUND); - mScrollArea->setDimension(gcn::Rectangle(5, 20 + 10, w - 10, h - 10 - 30)); - mScrollArea->setSize(w - 10, h - 10 - 30); - mBrowserBox->setLinkHandler(this); - - add(mUpdateButton); - add(mScrollArea); - - setLocationRelativeTo(getParent()); - - loadWindowState(); - enableVisibleSound(true); - - download(); - - widgetResized(gcn::Event(nullptr)); - config.addListener("updateOnlineList", this); - config.addListener("groupFriends", this); - mGroupFriends = config.getBoolValue("groupFriends"); -} - -WhoIsOnline::~WhoIsOnline() -{ - config.removeListeners(this); - - if (mThread && SDL_GetThreadID(mThread)) - SDL_WaitThread(mThread, nullptr); - - free(mMemoryBuffer); - mMemoryBuffer = nullptr; - - // Remove possibly leftover temporary download - delete []mCurlError; - - FOR_EACH (std::set::iterator, itd, mOnlinePlayers) - delete *itd; - mOnlinePlayers.clear(); - mOnlineNicks.clear(); -} - -void WhoIsOnline::handleLink(const std::string& link, gcn::MouseEvent *event) -{ - if (!event || event->getButton() == gcn::MouseEvent::LEFT) - { - if (chatWindow) - { - const std::string text = decodeLinkText(link); - if (config.getBoolValue("whispertab")) - { - chatWindow->localChatInput("/q " + text); - } - else - { - chatWindow->addInputText(std::string("/w \"").append( - text).append("\" ")); - } - } - } - else if (event->getButton() == gcn::MouseEvent::RIGHT) - { - if (player_node && link == player_node->getName()) - return; - - if (viewport) - { - if (actorSpriteManager) - { - const std::string text = decodeLinkText(link); - Being *const being = actorSpriteManager->findBeingByName( - text, Being::PLAYER); - - if (being && viewport) - { - viewport->showPopup(being); - return; - } - } - viewport->showPlayerPopup(link); - } - } -} - -void WhoIsOnline::updateWindow(std::vector &friends, - std::vector &neutral, - std::vector &disregard, - std::vector enemy, - size_t numOnline) -{ - // Set window caption - // TRANSLATORS: who is online window name - setCaption(_("Who Is Online - ") + toString(numOnline)); - - // List the online people - std::sort(friends.begin(), friends.end(), nameCompare); - std::sort(neutral.begin(), neutral.end(), nameCompare); - std::sort(disregard.begin(), disregard.end(), nameCompare); - bool addedFromSection(false); - FOR_EACH (std::vector::const_iterator, it, friends) - { - mBrowserBox->addRow((*it)->getText()); - addedFromSection = true; - } - if (addedFromSection == true) - { - mBrowserBox->addRow("---"); - addedFromSection = false; - } - FOR_EACH (std::vector::const_iterator, it, enemy) - { - mBrowserBox->addRow((*it)->getText()); - addedFromSection = true; - } - if (addedFromSection == true) - { - mBrowserBox->addRow("---"); - addedFromSection = false; - } - FOR_EACH (std::vector::const_iterator, it, neutral) - { - mBrowserBox->addRow((*it)->getText()); - addedFromSection = true; - } - if (addedFromSection == true && !disregard.empty()) - mBrowserBox->addRow("---"); - - FOR_EACH (std::vector::const_iterator, it, disregard) - mBrowserBox->addRow((*it)->getText()); - - if (mScrollArea->getVerticalMaxScroll() < - mScrollArea->getVerticalScrollAmount()) - { - mScrollArea->setVerticalScrollAmount( - mScrollArea->getVerticalMaxScroll()); - } -} - -void WhoIsOnline::loadList(std::vector &list) -{ - mBrowserBox->clearRows(); - const size_t numOnline = list.size(); - std::vector friends; - std::vector neutral; - std::vector disregard; - std::vector enemy; - - FOR_EACH (std::set::iterator, itd, mOnlinePlayers) - delete *itd; - mOnlinePlayers.clear(); - mOnlineNicks.clear(); - - mShowLevel = config.getBoolValue("showlevel"); - - FOR_EACH (std::vector::const_iterator, it, list) - { - OnlinePlayer *player = *it; - const std::string nick = player->getNick(); - mOnlinePlayers.insert(player); - mOnlineNicks.insert(nick); - - if (!mShowLevel) - player->setLevel(0); - - switch (player_relations.getRelation(nick)) - { - case PlayerRelation::NEUTRAL: - default: - setNeutralColor(player); - neutral.push_back(player); - break; - - case PlayerRelation::FRIEND: - player->setText("2"); - if (mGroupFriends) - friends.push_back(player); - else - neutral.push_back(player); - break; - - case PlayerRelation::DISREGARDED: - case PlayerRelation::BLACKLISTED: - player->setText("8"); - disregard.push_back(player); - break; - - case PlayerRelation::ENEMY2: - player->setText("1"); - enemy.push_back(player); - break; - - case PlayerRelation::IGNORED: - case PlayerRelation::ERASED: - // Ignore the ignored. - break; - } - } - - updateWindow(friends, neutral, disregard, enemy, numOnline); - if (!mOnlineNicks.empty()) - { - if (chatWindow) - chatWindow->updateOnline(mOnlineNicks); - if (socialWindow) - socialWindow->updateActiveList(); - } - updateSize(); -} - -void WhoIsOnline::loadWebList() -{ - if (!mMemoryBuffer) - return; - - // Reallocate and include terminating 0 character - mMemoryBuffer = static_cast( - realloc(mMemoryBuffer, mDownloadedBytes + 1)); - mMemoryBuffer[mDownloadedBytes] = '\0'; - - mBrowserBox->clearRows(); - bool listStarted(false); - std::string lineStr; - int numOnline(0); - std::vector friends; - std::vector neutral; - std::vector disregard; - std::vector enemy; - - // Tokenize and add each line separately - char *line = strtok(mMemoryBuffer, "\n"); - const std::string gmText("(GM)"); - - FOR_EACH (std::set::iterator, itd, mOnlinePlayers) - delete *itd; - - mOnlinePlayers.clear(); - mOnlineNicks.clear(); - - mShowLevel = config.getBoolValue("showlevel"); - - while (line) - { - std::string nick; - lineStr = line; - trim(lineStr); - if (listStarted == true) - { - if (lineStr.find(" users are online.") == std::string::npos) - { - if (lineStr.length() > 24) - { - nick = lineStr.substr(0, 24); - lineStr = lineStr.substr(25); - } - else - { - nick = lineStr; - lineStr.clear(); - } - trim(nick); - - bool isGM(false); - size_t pos = lineStr.find(gmText, 0); - if (pos != std::string::npos) - { - lineStr = lineStr.substr(pos + gmText.length()); - isGM = true; - } - - trim(lineStr); - pos = lineStr.find("/", 0); - - if (pos != std::string::npos) - lineStr = lineStr.substr(0, pos); - - int level = 0; - if (!lineStr.empty()) - level = atoi(lineStr.c_str()); - - if (actorSpriteManager) - { - Being *const being = actorSpriteManager->findBeingByName( - nick, Being::PLAYER); - if (being) - { - if (level > 0) - { - being->setLevel(level); - being->updateName(); - } - else - { - if (being->getLevel() > 1) - level = being->getLevel(); - } - } - } - - if (!mShowLevel) - level = 0; - - OnlinePlayer *const player = new OnlinePlayer(nick, - static_cast(255), level, - GENDER_UNSPECIFIED, -1); - mOnlinePlayers.insert(player); - mOnlineNicks.insert(nick); - - if (isGM) - player->setIsGM(true); - - numOnline++; - switch (player_relations.getRelation(nick)) - { - case PlayerRelation::NEUTRAL: - default: - setNeutralColor(player); - neutral.push_back(player); - break; - - case PlayerRelation::FRIEND: - player->setText("2"); - if (mGroupFriends) - friends.push_back(player); - else - neutral.push_back(player); - break; - - case PlayerRelation::DISREGARDED: - case PlayerRelation::BLACKLISTED: - player->setText("8"); - disregard.push_back(player); - break; - - case PlayerRelation::ENEMY2: - player->setText("1"); - enemy.push_back(player); - break; - - case PlayerRelation::IGNORED: - case PlayerRelation::ERASED: - // Ignore the ignored. - break; - } - } - } - else if (lineStr.find("------------------------------") - != std::string::npos) - { - listStarted = true; - } - line = strtok(nullptr, "\n"); - } - - updateWindow(friends, neutral, disregard, enemy, numOnline); - - // Free the memory buffer now that we don't need it anymore - free(mMemoryBuffer); - mMemoryBuffer = nullptr; -} - -size_t WhoIsOnline::memoryWrite(void *ptr, size_t size, - size_t nmemb, FILE *stream) -{ - if (!stream) - return 0; - - WhoIsOnline *const wio = reinterpret_cast(stream); - const size_t totalMem = size * nmemb; - wio->mMemoryBuffer = static_cast(realloc(wio->mMemoryBuffer, - wio->mDownloadedBytes + totalMem)); - if (wio->mMemoryBuffer) - { - memcpy(&(wio->mMemoryBuffer[wio->mDownloadedBytes]), ptr, totalMem); - wio->mDownloadedBytes += static_cast(totalMem); - } - - return totalMem; -} - -int WhoIsOnline::downloadThread(void *ptr) -{ - int attempts = 0; - WhoIsOnline *const wio = reinterpret_cast(ptr); - CURLcode res; - const std::string url(client->getOnlineUrl() + "/online.txt"); - - while (attempts < 1 && !wio->mDownloadComplete) - { - CURL *curl = curl_easy_init(); - if (curl) - { - if (!wio->mAllowUpdate) - { - curl_easy_cleanup(curl); - curl = nullptr; - break; - } - wio->mDownloadedBytes = 0; - curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, - WhoIsOnline::memoryWrite); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, ptr); - - curl_easy_setopt(curl, CURLOPT_USERAGENT, - strprintf(PACKAGE_EXTENDED_VERSION, - branding.getStringValue("appName").c_str()).c_str()); - - curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, wio->mCurlError); - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); - curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, ptr); - curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 7); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30); - Net::Download::addProxy(curl); - Net::Download::secureCurl(curl); - - // Make sure the resources2.txt and news.txt aren't cached, - // in order to always get the latest version. - struct curl_slist *pHeaders = nullptr; - pHeaders = curl_slist_append( - pHeaders, "pragma: no-cache"); - pHeaders = curl_slist_append(pHeaders, - "Cache-Control: no-cache"); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, pHeaders); - - if ((res = curl_easy_perform(curl)) != 0) - { - wio->mDownloadStatus = UPDATE_ERROR; - switch (res) - { - case CURLE_COULDNT_CONNECT: - default: - std::cerr << "curl error " - << static_cast(res) << ": " - << wio->mCurlError << " host: " - << url.c_str() << std::endl; - break; - } - attempts++; - curl_easy_cleanup(curl); - curl_slist_free_all(pHeaders); - curl = nullptr; - continue; - } - - curl_easy_cleanup(curl); - curl_slist_free_all(pHeaders); - - // It's stored in memory, we're done - wio->mDownloadComplete = true; - } - if (!wio->mAllowUpdate) - break; - attempts++; - } - - if (!wio->mDownloadComplete) - wio->mDownloadStatus = UPDATE_ERROR; - return 0; -} - -void WhoIsOnline::download() -{ - if (serverVersion < 3) - { - mDownloadComplete = true; - if (mThread && SDL_GetThreadID(mThread)) - SDL_WaitThread(mThread, nullptr); - - mDownloadComplete = false; - mThread = SDL::createThread(WhoIsOnline::downloadThread, - "whoisonline", this); - if (mThread == nullptr) - mDownloadStatus = UPDATE_ERROR; - } - else - { - if (client->limitPackets(PACKET_ONLINELIST)) - Net::getPlayerHandler()->requestOnlineList(); - } -} - -void WhoIsOnline::logic() -{ - BLOCK_START("WhoIsOnline::logic") - mScrollArea->logic(); - BLOCK_END("WhoIsOnline::logic") -} - -void WhoIsOnline::slowLogic() -{ - if (!mAllowUpdate) - return; - - BLOCK_START("WhoIsOnline::slowLogic") - if (mUpdateTimer == 0) - mUpdateTimer = cur_time; - - const double timeDiff = difftime(cur_time, mUpdateTimer); - const int timeLimit = isWindowVisible() ? 20 : 120; - - if (mUpdateOnlineList && timeDiff >= timeLimit - && mDownloadStatus != UPDATE_LIST) - { - if (mDownloadComplete == true) - { - // TRANSLATORS: who is online window name - setCaption(_("Who Is Online - Updating")); - mUpdateTimer = 0; - mDownloadStatus = UPDATE_LIST; - download(); - } - } - - switch (mDownloadStatus) - { - case UPDATE_ERROR: - mBrowserBox->clearRows(); - mBrowserBox->addRow("##1Failed to fetch the online list!"); - mBrowserBox->addRow(mCurlError); - mDownloadStatus = UPDATE_COMPLETE; - // TRANSLATORS: who is online window name - setCaption(_("Who Is Online - error")); - mUpdateButton->setEnabled(true); - mUpdateTimer = cur_time + 240; - mDownloadComplete = true; - updateSize(); - break; - case UPDATE_LIST: - if (mDownloadComplete == true) - { - loadWebList(); - mDownloadStatus = UPDATE_COMPLETE; - mUpdateButton->setEnabled(true); - mUpdateTimer = 0; - updateSize(); - if (!mOnlineNicks.empty()) - { - if (chatWindow) - chatWindow->updateOnline(mOnlineNicks); - if (socialWindow) - socialWindow->updateActiveList(); - } - } - break; - case UPDATE_COMPLETE: - default: - break; - } - BLOCK_END("WhoIsOnline::slowLogic") -} - -void WhoIsOnline::action(const gcn::ActionEvent &event) -{ - if (event.getId() == "update") - { - if (serverVersion < 3) - { - if (mDownloadStatus == UPDATE_COMPLETE) - { - mUpdateTimer = cur_time - 20; - if (mUpdateButton) - mUpdateButton->setEnabled(false); - // TRANSLATORS: who is online window name - setCaption(_("Who Is Online - Update")); - if (mThread && SDL_GetThreadID(mThread)) - { - SDL_WaitThread(mThread, nullptr); - mThread = nullptr; - } - mDownloadComplete = true; - } - } - else - { - if (client->limitPackets(PACKET_ONLINELIST)) - { - mUpdateTimer = cur_time; - Net::getPlayerHandler()->requestOnlineList(); - } - } - } -} - -void WhoIsOnline::widgetResized(const gcn::Event &event) -{ - Window::widgetResized(event); - updateSize(); -} - -void WhoIsOnline::updateSize() -{ - const gcn::Rectangle area = getChildrenArea(); - if (mUpdateButton) - mUpdateButton->setWidth(area.width - 10); - - if (mScrollArea) - mScrollArea->setSize(area.width - 10, area.height - 10 - 30); - if (mBrowserBox) - mBrowserBox->setWidth(area.width - 10); -} - -const std::string WhoIsOnline::prepareNick(const std::string &nick, - const int level, - const std::string &color) const -{ - const std::string text = encodeLinkText(nick); - if (mShowLevel && level > 1) - { - return strprintf("@@%s|##%s%s (%d)@@", text.c_str(), - color.c_str(), text.c_str(), level); - } - else - { - return strprintf("@@%s|##%s%s@@", text.c_str(), - color.c_str(), text.c_str()); - } -} - -void WhoIsOnline::optionChanged(const std::string &name) -{ - if (name == "updateOnlineList") - mUpdateOnlineList = config.getBoolValue("updateOnlineList"); - else if (name == "groupFriends") - mGroupFriends = config.getBoolValue("groupFriends"); -} - -void WhoIsOnline::setNeutralColor(OnlinePlayer *const player) -{ - if (!player) - return; - - if (actorSpriteManager && player_node) - { - const std::string &nick = player->getNick(); - if (nick == player_node->getName()) - { - player->setText("s"); - return; - } - if (player_node->isInParty()) - { - const Party *const party = player_node->getParty(); - if (party) - { - if (party->getMember(nick)) - { - player->setText("P"); - return; - } - } - } - - const Being *const being = actorSpriteManager->findBeingByName(nick); - if (being) - { - const Guild *const guild2 = player_node->getGuild(); - if (guild2) - { - const Guild *const guild1 = being->getGuild(); - if (guild1) - { - if (guild1->getId() == guild2->getId() - || guild2->getMember(nick)) - { - player->setText("U"); - return; - } - } - else if (guild2->isMember(nick)) - { - player->setText("U"); - return; - } - } - } - const Guild *const guild3 = Guild::getGuild(1); - if (guild3 && guild3->isMember(nick)) - { - player->setText("U"); - return; - } - } - player->setText("0"); -} - -void WhoIsOnline::getPlayerNames(StringVect &names) -{ - names.clear(); - FOR_EACH (std::set::const_iterator, it, mOnlineNicks) - names.push_back(*it); -} - -void OnlinePlayer::setText(std::string color) -{ - mText.clear(); - - if (mStatus != 255 && actorSpriteManager) - { - Being *const being = actorSpriteManager->findBeingByName( - mNick, Being::PLAYER); - if (being) - { - being->setState(mStatus); - // for now highlight versions > 3 - if (mVersion > 3) - being->setAdvanced(true); - } - } - - if ((mStatus != 255 && mStatus & Being::FLAG_GM) || mIsGM) - mText.append("(GM) "); - - if (mLevel > 0) - mText.append(strprintf("%d", mLevel)); - - if (mGender == GENDER_FEMALE) - mText.append("\u2640"); - else if (mGender == GENDER_MALE) - mText.append("\u2642"); - - if (mStatus > 0 && mStatus != 255) - { - if (mStatus & Being::FLAG_SHOP) - mText.append("$"); - if (mStatus & Being::FLAG_AWAY) - { - // TRANSLATORS: this away status writed in player nick - mText.append(_("A")); - } - if (mStatus & Being::FLAG_INACTIVE) - { - // TRANSLATORS: this inactive status writed in player nick - mText.append(_("I")); - } - - if (mStatus & Being::FLAG_GM && color == "0") - color = "2"; - } - else if (mIsGM && color == "0") - { - color = "2"; - } - - if (mVersion > 0) - mText.append(strprintf(" - %d", mVersion)); - - const std::string text = encodeLinkText(mNick); - mText = strprintf("@@%s|##%s%s %s@@", text.c_str(), color.c_str(), - text.c_str(), mText.c_str()); -} diff --git a/src/gui/whoisonline.h b/src/gui/whoisonline.h deleted file mode 100644 index 860eeacda..000000000 --- a/src/gui/whoisonline.h +++ /dev/null @@ -1,223 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 Andrei Karas - * Copyright (C) 2011-2013 The ManaPlus developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_WHOISONLINE_H -#define GUI_WHOISONLINE_H - -#include "configlistener.h" - -#include "gui/widgets/linkhandler.h" -#include "gui/widgets/window.h" - -#include - -#include - -class BrowserBox; -class Button; -class ScrollArea; - -struct SDL_Thread; - -class OnlinePlayer final -{ - public: - OnlinePlayer(const std::string &nick, const unsigned char status, - const char level, const unsigned char gender, - const char version) : - mNick(nick), - mText(""), - mStatus(status), - mLevel(level), - mVersion(version), - mGender(gender), - mIsGM(false) - { - } - - A_DELETE_COPY(OnlinePlayer) - - const std::string getNick() const A_WARN_UNUSED - { return mNick; } - - unsigned char getStaus() const A_WARN_UNUSED - { return mStatus; } - - void setIsGM(const bool b) - { mIsGM = b; } - - char getVersion() const A_WARN_UNUSED - { return mVersion; } - - char getLevel() const A_WARN_UNUSED - { return mLevel; } - - const std::string getText() const A_WARN_UNUSED - { return mText; } - - void setText(std::string str); - - void setLevel(const char level) - { mLevel = level; } - - private: - std::string mNick; - - std::string mText; - - unsigned char mStatus; - - char mLevel; - - char mVersion; - - unsigned char mGender; - - bool mIsGM; -}; - -/** - * Update progress window GUI - * - * \ingroup GUI - */ -class WhoIsOnline final : public Window, - public LinkHandler, - public gcn::ActionListener, - public ConfigListener -{ -public: - /** - * Constructor. - */ - WhoIsOnline(); - - A_DELETE_COPY(WhoIsOnline) - - /** - * Destructor - */ - ~WhoIsOnline(); - - /** - * Loads and display online list from the memory buffer. - */ - void loadWebList(); - - void loadList(std::vector &list); - - void handleLink(const std::string& link, gcn::MouseEvent *event) override; - - void logic() override; - - void slowLogic(); - - void action(const gcn::ActionEvent &event) override; - - void widgetResized(const gcn::Event &event) override; - - const std::set &getOnlinePlayers() const A_WARN_UNUSED - { return mOnlinePlayers; } - - const std::set &getOnlineNicks() const A_WARN_UNUSED - { return mOnlineNicks; } - - void setAllowUpdate(const bool n) - { mAllowUpdate = n; } - - void optionChanged(const std::string &name) override; - - void updateList(StringVect &list); - - void readFromWeb(); - - void setNeutralColor(OnlinePlayer *const player); - - void getPlayerNames(StringVect &names); - -private: - void download(); - - void updateSize(); - - /** - * The thread function that download the files. - */ - static int downloadThread(void *ptr); - - /** - * A libcurl callback for writing to memory. - */ - static size_t memoryWrite(void *ptr, size_t size, size_t nmemb, - FILE *stream); - - const std::string prepareNick(const std::string &nick, const int level, - const std::string &color) - const A_WARN_UNUSED; - - void updateWindow(std::vector &friends, - std::vector &neutral, - std::vector &disregard, - std::vector enemy, - size_t numOnline); - - enum DownloadStatus - { - UPDATE_ERROR = 0, - UPDATE_COMPLETE, - UPDATE_LIST - }; - - /** A thread that use libcurl to download updates. */ - SDL_Thread *mThread; - - /** Status of the current download. */ - DownloadStatus mDownloadStatus; - - /** Flag that show if current download is complete. */ - bool mDownloadComplete; - - /** Byte count currently downloaded in mMemoryBuffer. */ - int mDownloadedBytes; - - /** Buffer for files downloaded to memory. */ - char *mMemoryBuffer; - - /** Buffer to handler human readable error provided by curl. */ - char *mCurlError; - - BrowserBox *mBrowserBox; - ScrollArea *mScrollArea; - time_t mUpdateTimer; - std::set mOnlinePlayers; - std::set mOnlineNicks; - - Button *mUpdateButton; - bool mAllowUpdate; - bool mShowLevel; - bool mUpdateOnlineList; - bool mGroupFriends; -}; - -extern WhoIsOnline *whoIsOnline; - -#endif // GUI_WHOISONLINE_H diff --git a/src/gui/widgets/avatarlistbox.cpp b/src/gui/widgets/avatarlistbox.cpp index 8b65928a8..76b5ccfc4 100644 --- a/src/gui/widgets/avatarlistbox.cpp +++ b/src/gui/widgets/avatarlistbox.cpp @@ -28,11 +28,12 @@ #include "being/localplayer.h" -#include "gui/chatwindow.h" #include "gui/gui.h" #include "gui/sdlfont.h" #include "gui/viewport.h" +#include "gui/windows/chatwindow.h" + #include "resources/image.h" #include diff --git a/src/gui/widgets/characterdisplay.cpp b/src/gui/widgets/characterdisplay.cpp index 65812ba4b..c8a38337f 100644 --- a/src/gui/widgets/characterdisplay.cpp +++ b/src/gui/widgets/characterdisplay.cpp @@ -24,7 +24,8 @@ #include "units.h" -#include "gui/charselectdialog.h" +#include "gui/windows/charselectdialog.h" + #include "gui/textpopup.h" #include "gui/widgets/label.h" diff --git a/src/gui/widgets/characterviewbase.h b/src/gui/widgets/characterviewbase.h index 8ef949b7c..21e20e37d 100644 --- a/src/gui/widgets/characterviewbase.h +++ b/src/gui/widgets/characterviewbase.h @@ -21,7 +21,7 @@ #ifndef GUI_WIDGETS_CHARACTERVIEWBASE_H #define GUI_WIDGETS_CHARACTERVIEWBASE_H -#include "gui/charselectdialog.h" +#include "gui/windows/charselectdialog.h" #include "gui/widgets/container.h" diff --git a/src/gui/widgets/chattab.cpp b/src/gui/widgets/chattab.cpp index aba79034f..e863643d3 100644 --- a/src/gui/widgets/chattab.cpp +++ b/src/gui/widgets/chattab.cpp @@ -31,7 +31,7 @@ #include "being/localplayer.h" -#include "gui/helpwindow.h" +#include "gui/windows/helpwindow.h" #include "gui/widgets/scrollarea.h" #include "gui/widgets/itemlinkhandler.h" diff --git a/src/gui/widgets/chattab.h b/src/gui/widgets/chattab.h index c2ac5a45b..07192ab6b 100644 --- a/src/gui/widgets/chattab.h +++ b/src/gui/widgets/chattab.h @@ -23,7 +23,7 @@ #ifndef GUI_WIDGETS_CHATTAB_H #define GUI_WIDGETS_CHATTAB_H -#include "gui/chatwindow.h" +#include "gui/windows/chatwindow.h" #include "gui/widgets/browserbox.h" #include "gui/widgets/tab.h" diff --git a/src/gui/widgets/dropshortcutcontainer.cpp b/src/gui/widgets/dropshortcutcontainer.cpp index 115fcb192..c040d4c3a 100644 --- a/src/gui/widgets/dropshortcutcontainer.cpp +++ b/src/gui/widgets/dropshortcutcontainer.cpp @@ -28,10 +28,11 @@ #include "being/playerinfo.h" -#include "gui/inventorywindow.h" #include "gui/itempopup.h" #include "gui/viewport.h" +#include "gui/windows/inventorywindow.h" + #include "resources/image.h" #include diff --git a/src/gui/widgets/itemcontainer.cpp b/src/gui/widgets/itemcontainer.cpp index 0def0ad9e..64cafcd82 100644 --- a/src/gui/widgets/itemcontainer.cpp +++ b/src/gui/widgets/itemcontainer.cpp @@ -29,13 +29,14 @@ #include "being/playerinfo.h" -#include "gui/chatwindow.h" #include "gui/gui.h" #include "gui/itempopup.h" -#include "gui/shopwindow.h" -#include "gui/shortcutwindow.h" #include "gui/viewport.h" +#include "gui/windows/chatwindow.h" +#include "gui/windows/shopwindow.h" +#include "gui/windows/shortcutwindow.h" + #include "net/net.h" #include "net/inventoryhandler.h" #include "net/tradehandler.h" diff --git a/src/gui/widgets/itemlinkhandler.cpp b/src/gui/widgets/itemlinkhandler.cpp index fd70e2032..0dff139f6 100644 --- a/src/gui/widgets/itemlinkhandler.cpp +++ b/src/gui/widgets/itemlinkhandler.cpp @@ -22,11 +22,12 @@ #include "gui/widgets/itemlinkhandler.h" -#include "gui/confirmdialog.h" -#include "gui/helpwindow.h" #include "gui/itempopup.h" #include "gui/viewport.h" +#include "gui/windows/confirmdialog.h" +#include "gui/windows/helpwindow.h" + #include "utils/gettext.h" #include "utils/process.h" #include "utils/stringutils.h" diff --git a/src/gui/widgets/itemshortcutcontainer.cpp b/src/gui/widgets/itemshortcutcontainer.cpp index 3334a42e5..e2901c3bb 100644 --- a/src/gui/widgets/itemshortcutcontainer.cpp +++ b/src/gui/widgets/itemshortcutcontainer.cpp @@ -33,12 +33,13 @@ #include "input/inputmanager.h" -#include "gui/inventorywindow.h" #include "gui/itempopup.h" -#include "gui/skilldialog.h" #include "gui/spellpopup.h" #include "gui/viewport.h" +#include "gui/windows/inventorywindow.h" +#include "gui/windows/skilldialog.h" + #include "gui/widgets/skillinfo.h" #include "resources/image.h" diff --git a/src/gui/widgets/setupitem.cpp b/src/gui/widgets/setupitem.cpp index 652a1402b..0cbfd1a5e 100644 --- a/src/gui/widgets/setupitem.cpp +++ b/src/gui/widgets/setupitem.cpp @@ -24,10 +24,11 @@ #include "main.h" #include "soundmanager.h" -#include "gui/editdialog.h" #include "gui/gui.h" #include "gui/sdlfont.h" +#include "gui/windows/editdialog.h" + #include "gui/widgets/checkbox.h" #include "gui/widgets/dropdown.h" #include "gui/widgets/horizontcontainer.h" diff --git a/src/gui/widgets/spellshortcutcontainer.cpp b/src/gui/widgets/spellshortcutcontainer.cpp index cf3fc937b..8e77d3215 100644 --- a/src/gui/widgets/spellshortcutcontainer.cpp +++ b/src/gui/widgets/spellshortcutcontainer.cpp @@ -27,11 +27,12 @@ #include "itemshortcut.h" #include "spellshortcut.h" -#include "gui/inventorywindow.h" -#include "gui/shortcutwindow.h" #include "gui/spellpopup.h" #include "gui/viewport.h" +#include "gui/windows/inventorywindow.h" +#include "gui/windows/shortcutwindow.h" + #include "resources/image.h" #include diff --git a/src/gui/windowmenu.cpp b/src/gui/windowmenu.cpp index 39674e860..46b905045 100644 --- a/src/gui/windowmenu.cpp +++ b/src/gui/windowmenu.cpp @@ -26,12 +26,13 @@ #include "input/inputmanager.h" -#include "gui/skilldialog.h" +#include "gui/textpopup.h" +#include "gui/viewport.h" + +#include "gui/windows/skilldialog.h" #ifdef MANASERV_SUPPORT #include "gui/specialswindow.h" #endif -#include "gui/textpopup.h" -#include "gui/viewport.h" #include "utils/dtor.h" #include "utils/gettext.h" diff --git a/src/gui/windows/botcheckerwindow.cpp b/src/gui/windows/botcheckerwindow.cpp new file mode 100644 index 000000000..f51683b40 --- /dev/null +++ b/src/gui/windows/botcheckerwindow.cpp @@ -0,0 +1,421 @@ +/* + * The ManaPlus Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 Andrei Karas + * Copyright (C) 2011-2013 The ManaPlus developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/botcheckerwindow.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/scrollarea.h" +#include "gui/widgets/label.h" +#include "gui/widgets/guitable.h" + +#include "actorspritemanager.h" +#include "configuration.h" + +#include "being/localplayer.h" + +#include "utils/gettext.h" + +#include + +#include "debug.h" + +const int COLUMNS_NR = 5; // name plus listbox +const int NAME_COLUMN = 0; +const int TIME_COLUMN = 1; + +const int ROW_HEIGHT = 12; +// The following column widths really shouldn't be hardcoded but should +// scale with the size of the widget... excep +// that, right now, the widget doesn't exactly scale either. +const int NAME_COLUMN_WIDTH = 185; +const int TIME_COLUMN_WIDTH = 70; + +#define WIDGET_AT(row, column) (((row) * COLUMNS_NR) + column) + +class UsersTableModel final : public TableModel, + public Widget2 +{ +public: + explicit UsersTableModel(const Widget2 *const widget) : + TableModel(), + Widget2(widget), + mPlayers(0), + mWidgets() + { + playersUpdated(); + } + + A_DELETE_COPY(UsersTableModel) + + ~UsersTableModel() + { + freeWidgets(); + } + + int getRows() const + { + return static_cast(mPlayers.size()); + } + + int getColumns() const + { + return COLUMNS_NR; + } + + int getRowHeight() const + { + return ROW_HEIGHT; + } + + int getColumnWidth(const int index) const + { + if (index == NAME_COLUMN) + return NAME_COLUMN_WIDTH; + else + return TIME_COLUMN_WIDTH; + } + + void playersUpdated() + { + signalBeforeUpdate(); + + freeWidgets(); + mPlayers.clear(); + if (actorSpriteManager && botCheckerWindow + && botCheckerWindow->mEnabled) + { + std::set beings = actorSpriteManager->getAll(); + FOR_EACH (ActorSprites::const_iterator, i, beings) + { + Being *const being = dynamic_cast(*i); + + if (being && being->getType() == Being::PLAYER + && being != player_node && being->getName() != "") + { + mPlayers.push_back(being); + } + } + } + + const unsigned int curTime = cur_time; + const unsigned int sz = mPlayers.size(); + // set up widgets + for (unsigned int r = 0; r < sz; ++r) + { + if (!mPlayers.at(r)) + continue; + + const Being *const player = mPlayers.at(r); + gcn::Widget *widget = new Label(this, player->getName()); + + mWidgets.push_back(widget); + + if (player->getAttackTime() != 0) + { + widget = new Label(this, toString(curTime + - player->getAttackTime())); + } + else + { + widget = new Label(this, toString(curTime + - player->getTestTime()).append("?")); + } + mWidgets.push_back(widget); + + if (player->getTalkTime() != 0) + { + widget = new Label(this, toString(curTime + - player->getTalkTime())); + } + else + { + widget = new Label(this, toString(curTime + - player->getTestTime()).append("?")); + } + mWidgets.push_back(widget); + + if (player->getMoveTime() != 0) + { + widget = new Label(this, toString(curTime + - player->getMoveTime())); + } + else + { + widget = new Label(this, toString(curTime + - player->getTestTime()).append("?")); + } + mWidgets.push_back(widget); + + std::string str; + bool talkBot = false; + bool moveBot = false; + bool attackBot = false; + bool otherBot = false; + + if (curTime - player->getTestTime() > 2 * 60) + { + const int attack = curTime - (player->getAttackTime() + ? player->getAttackTime() + : player->getTestTime()); + const int talk = curTime - (player->getTalkTime() + ? player->getTalkTime() + : player->getTestTime()) - attack; + const int move = curTime - (player->getMoveTime() + ? player->getMoveTime() + : player->getTestTime()) - attack; + const int other = curTime - (player->getOtherTime() + ? player->getMoveTime() + : player->getOtherTime()) - attack; + + if (attack < 2 * 60) + attackBot = true; + + // attacking but not talking more than 2 minutes + if (talk > 2 * 60) + { + talkBot = true; + str.append(toString((talk) / 60)).append(" "); + } + + // attacking but not moving more than 2 minutes + if (move > 2 * 60) + { + moveBot = true; + str.append(toString((move) / 60)); + } + + // attacking but not other activity more than 2 minutes + if (move > 2 * 60 && other > 2 * 60) + otherBot = true; + } + + if (str.length() > 0) + { + if (attackBot && talkBot && moveBot && otherBot) + str = "bot!! " + str; + else if (attackBot && talkBot && moveBot) + str = "bot! " + str; + else if (talkBot && moveBot) + str = "bot " + str; + else if (talkBot || moveBot) + str = "bot? " + str; + } + else + { + str = "ok"; + } + + widget = new Label(this, str); + mWidgets.push_back(widget); + } + + signalAfterUpdate(); + } + + void updateModelInRow(const int row A_UNUSED) const + { + } + + gcn::Widget *getElementAt(const int row, const int column) const + { + return mWidgets[WIDGET_AT(row, column)]; + } + + void freeWidgets() + { + for (std::vector::const_iterator it = mWidgets.begin(); + it != mWidgets.end(); ++it) + { + delete *it; + } + + mWidgets.clear(); + } + +protected: + std::vector mPlayers; + std::vector mWidgets; +}; + + +BotCheckerWindow::BotCheckerWindow(): + // TRANSLATORS: bot checker window header + Window(_("Bot Checker"), false, nullptr, "botchecker.xml"), + gcn::ActionListener(), + mTableModel(new UsersTableModel(this)), + mTable(new GuiTable(this, mTableModel)), + playersScrollArea(new ScrollArea(mTable, true, + "bochecker_background.xml")), + mPlayerTableTitleModel(new StaticTableModel(1, COLUMNS_NR)), + mPlayerTitleTable(new GuiTable(this, mPlayerTableTitleModel)), + // TRANSLATORS: bot checker window button + mIncButton(new Button(this, _("Reset"), "reset", this)), + mLastUpdateTime(0), + mNeedUpdate(false), + mEnabled(false) +{ + const int w = 500; + const int h = 250; + + setSaveVisible(true); + + mTable->setOpaque(false); + mTable->setLinewiseSelection(true); + mTable->setWrappingEnabled(true); + mTable->setActionEventId("skill"); + mTable->addActionListener(this); + + mPlayerTableTitleModel->fixColumnWidth(NAME_COLUMN, NAME_COLUMN_WIDTH); + + for (int f = 0; f < 4; f++) + { + mPlayerTableTitleModel->fixColumnWidth( + TIME_COLUMN + f, TIME_COLUMN_WIDTH); + } + + mPlayerTitleTable->setHeight(1); + + // TRANSLATORS: bot checker window table header + mPlayerTableTitleModel->set(0, 0, new Label(this, _("Name"))); + // TRANSLATORS: bot checker window table header + mPlayerTableTitleModel->set(0, 1, new Label(this, _("Attack"))); + // TRANSLATORS: bot checker window table header + mPlayerTableTitleModel->set(0, 2, new Label(this, _("Talk"))); + // TRANSLATORS: bot checker window table header + mPlayerTableTitleModel->set(0, 3, new Label(this, _("Move"))); + // TRANSLATORS: bot checker window table header + mPlayerTableTitleModel->set(0, 4, new Label(this, _("Result"))); + + mPlayerTitleTable->setLinewiseSelection(true); + + setWindowName("BotCheckerWindow"); + setCloseButton(true); + setStickyButtonLock(true); + setDefaultSize(w, h, ImageRect::CENTER); + + playersScrollArea->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); + + mPlayerTitleTable->setPosition(mPadding, mPadding); + mPlayerTitleTable->setWidth(w - 10); + mPlayerTitleTable->setHeight(20); + + playersScrollArea->setPosition(mPadding, 20 + 2 * mPadding); + playersScrollArea->setWidth(w - 15); + playersScrollArea->setHeight(h - 80); + + mIncButton->setPosition(mPadding, 190 + 3 * mPadding); + mIncButton->setWidth(80); + mIncButton->setHeight(20); + + add(mPlayerTitleTable); + add(playersScrollArea); + add(mIncButton); + + center(); + + setWidth(w); + setHeight(h); + loadWindowState(); + enableVisibleSound(true); + + config.addListener("enableBotCheker", this); + mEnabled = config.getBoolValue("enableBotCheker"); +} + +BotCheckerWindow::~BotCheckerWindow() +{ + config.removeListener("enableBotCheker", this); +} + +void BotCheckerWindow::slowLogic() +{ + BLOCK_START("BotCheckerWindow::slowLogic") + if (mEnabled && mTableModel) + { + const unsigned int nowTime = cur_time; + if (nowTime - mLastUpdateTime > 5 && mNeedUpdate) + { + mTableModel->playersUpdated(); + mNeedUpdate = false; + mLastUpdateTime = nowTime; + } + else if (nowTime - mLastUpdateTime > 15) + { + mTableModel->playersUpdated(); + mNeedUpdate = false; + mLastUpdateTime = nowTime; + } + } + BLOCK_END("BotCheckerWindow::slowLogic") +} + +void BotCheckerWindow::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "reset") + { + reset(); + mNeedUpdate = true; + } +} + +void BotCheckerWindow::update() +{ +} + +void BotCheckerWindow::updateList() +{ + if (mTableModel) + mNeedUpdate = true; +} + +void BotCheckerWindow::reset() +{ + if (actorSpriteManager) + { + std::set beings = actorSpriteManager->getAll(); + FOR_EACH (ActorSprites::const_iterator, i, beings) + { + Being *const being = dynamic_cast(*i); + + if (being && being->getType() == Being::PLAYER + && being != player_node && being->getName() != "") + { + being->resetCounters(); + } + } + } +} + +void BotCheckerWindow::optionChanged(const std::string &name) +{ + if (name == "enableBotCheker") + mEnabled = config.getBoolValue("enableBotCheker"); +} + +#ifdef USE_PROFILER +void BotCheckerWindow::logicChildren() +{ + BLOCK_START("BotCheckerWindow::logicChildren") + BasicContainer::logicChildren(); + BLOCK_END("BotCheckerWindow::logicChildren") +} +#endif diff --git a/src/gui/windows/botcheckerwindow.h b/src/gui/windows/botcheckerwindow.h new file mode 100644 index 000000000..fbe53cf82 --- /dev/null +++ b/src/gui/windows/botcheckerwindow.h @@ -0,0 +1,94 @@ +/* + * The ManaPlus Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 Andrei Karas + * Copyright (C) 2011-2013 The ManaPlus developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_BOTCHECKERWINDOW_H +#define GUI_BOTCHECKERWINDOW_H + +#include "configlistener.h" + +#include "gui/widgets/window.h" + +#include + +struct BOTCHK final +{ + int16_t id; /**< Index into "botchecker_db" array */ + int16_t lv; + int16_t sp; +}; + +class Button; +class GuiTable; +class ScrollArea; +class UsersTableModel; +class StaticTableModel; + +class BotCheckerWindow final : public Window, + public gcn::ActionListener, + public ConfigListener +{ + public: + friend class UsersTableModel; + + /** + * Constructor. + */ + BotCheckerWindow(); + + A_DELETE_COPY(BotCheckerWindow) + + /** + * Destructor. + */ + ~BotCheckerWindow(); + + void action(const gcn::ActionEvent &event) override; + + void update(); + + void slowLogic(); + + void updateList(); + + void reset(); + + void optionChanged(const std::string &name) override; + +#ifdef USE_PROFILER + void logicChildren(); +#endif + + private: + UsersTableModel *mTableModel; + GuiTable *mTable; + ScrollArea *playersScrollArea; + StaticTableModel *mPlayerTableTitleModel; + GuiTable *mPlayerTitleTable; + Button *mIncButton; + int mLastUpdateTime; + bool mNeedUpdate; + bool mEnabled; +}; + +extern BotCheckerWindow *botCheckerWindow; + +#endif // GUI_BOTCHECKERWINDOW_H diff --git a/src/gui/windows/buydialog.cpp b/src/gui/windows/buydialog.cpp new file mode 100644 index 000000000..44b143e50 --- /dev/null +++ b/src/gui/windows/buydialog.cpp @@ -0,0 +1,553 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/buydialog.h" + +#include "shopitem.h" +#include "units.h" + +#include "gui/windows/tradewindow.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/dropdown.h" +#include "gui/widgets/inttextfield.h" +#include "gui/widgets/label.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/scrollarea.h" +#include "gui/widgets/shopitems.h" +#include "gui/widgets/shoplistbox.h" +#include "gui/widgets/slider.h" + +#include "net/adminhandler.h" +#include "net/buysellhandler.h" +#include "net/net.h" +#include "net/npchandler.h" + +#include "resources/iteminfo.h" + +#include "utils/gettext.h" + +#include + +#include "debug.h" + +static const char *const SORT_NAME_BUY[7] = +{ + // TRANSLATORS: buy dialog sort type. + N_("unsorted"), + // TRANSLATORS: buy dialog sort type. + N_("by price"), + // TRANSLATORS: buy dialog sort type. + N_("by name"), + // TRANSLATORS: buy dialog sort type. + N_("by id"), + // TRANSLATORS: buy dialog sort type. + N_("by weight"), + // TRANSLATORS: buy dialog sort type. + N_("by amount"), + // TRANSLATORS: buy dialog sort type. + N_("by type") +}; + +class SortListModelBuy final : public gcn::ListModel +{ +public: + ~SortListModelBuy() + { } + + int getNumberOfElements() + { return 7; } + + std::string getElementAt(int i) + { + if (i >= getNumberOfElements() || i < 0) + return "???"; + return gettext(SORT_NAME_BUY[i]); + } +}; + +class SortItemPriceFunctor final +{ + public: + bool operator() (const ShopItem *const item1, + const ShopItem *const item2) const + { + if (!item1 || !item2) + return false; + + const int price1 = item1->getPrice(); + const int price2 = item2->getPrice(); + if (price1 == price2) + return item1->getDisplayName() < item2->getDisplayName(); + return price1 < price2; + } +} itemPriceBuySorter; + +class SortItemNameFunctor final +{ + public: + bool operator() (const ShopItem *const item1, + const ShopItem *const item2) const + { + if (!item1 || !item2) + return false; + + const std::string &name1 = item1->getDisplayName(); + const std::string &name2 = item2->getDisplayName(); + if (name1 == name2) + return item1->getPrice() < item2->getPrice(); + return name1 < name2; + } +} itemNameBuySorter; + +class SortItemIdFunctor final +{ + public: + bool operator() (const ShopItem *const item1, + const ShopItem *const item2) const + { + if (!item1 || !item2) + return false; + + const int id1 = item1->getId(); + const int id2 = item2->getId(); + if (id1 == id2) + return item1->getPrice() < item2->getPrice(); + return id1 < id2; + } +} itemIdBuySorter; + +class SortItemWeightFunctor final +{ + public: + bool operator() (const ShopItem *const item1, + const ShopItem *const item2) const + { + if (!item1 || !item2) + return false; + + const int weight1 = item1->getInfo().getWeight(); + const int weight2 = item2->getInfo().getWeight(); + if (weight1 == weight2) + return item1->getPrice() < item2->getPrice(); + return weight1 < weight2; + } +} itemWeightBuySorter; + +class SortItemAmountFunctor final +{ + public: + bool operator() (const ShopItem *const item1, + const ShopItem *const item2) const + { + if (!item1 || !item2) + return false; + + const int amount1 = item1->getQuantity(); + const int amount2 = item2->getQuantity(); + if (amount1 == amount2) + return item1->getPrice() < item2->getPrice(); + return amount1 < amount2; + } +} itemAmountBuySorter; + +class SortItemTypeFunctor final +{ + public: + bool operator() (const ShopItem *const item1, + const ShopItem *const item2) const + { + if (!item1 || !item2) + return false; + + const int type1 = item1->getInfo().getType(); + const int type2 = item2->getInfo().getType(); + if (type1 == type2) + return item1->getPrice() < item2->getPrice(); + return type1 < type2; + } +} itemTypeBuySorter; + +BuyDialog::DialogList BuyDialog::instances; + +BuyDialog::BuyDialog() : + // TRANSLATORS: buy dialog name + Window(_("Create items"), false, nullptr, "buy.xml"), + gcn::ActionListener(), + gcn::SelectionListener(), + mNpcId(-2), mMoney(0), mAmountItems(0), mMaxItems(0), mNick(), + mSortModel(nullptr), + mSortDropDown(nullptr) +{ + init(); +} + +BuyDialog::BuyDialog(const int npcId) : + // TRANSLATORS: buy dialog name + Window(_("Buy"), false, nullptr, "buy.xml"), + gcn::ActionListener(), + gcn::SelectionListener(), + mNpcId(npcId), mMoney(0), mAmountItems(0), mMaxItems(0), mNick(), + mSortModel(nullptr), + mSortDropDown(nullptr) +{ + init(); +} + +BuyDialog::BuyDialog(std::string nick) : + // TRANSLATORS: buy dialog name + Window(_("Buy"), false, nullptr, "buy.xml"), + gcn::ActionListener(), + gcn::SelectionListener(), + mNpcId(-1), mMoney(0), mAmountItems(0), mMaxItems(0), mNick(nick), + mSortModel(new SortListModelBuy), + mSortDropDown(new DropDown(this, mSortModel, false, false, this, "sort")) +{ + init(); +} + +void BuyDialog::init() +{ + setWindowName("Buy"); + setResizable(true); + setCloseButton(true); + setStickyButtonLock(true); + setMinWidth(260); + setMinHeight(220); + setDefaultSize(260, 230, ImageRect::CENTER); + + mShopItems = new ShopItems; + + mShopItemList = new ShopListBox(this, mShopItems, mShopItems); + mScrollArea = new ScrollArea(mShopItemList, + getOptionBool("showbackground"), "buy_background.xml"); + mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + + mSlider = new Slider(1.0); + mQuantityLabel = new Label(this, strprintf( + "%d / %d", mAmountItems, mMaxItems)); + mQuantityLabel->setAlignment(gcn::Graphics::CENTER); + // TRANSLATORS: buy dialog label + mMoneyLabel = new Label(this, strprintf( + _("Price: %s / Total: %s"), "", "")); + + mAmountField = new IntTextField(this, 1, 1, 123); + mAmountField->setActionEventId("amount"); + mAmountField->addActionListener(this); + mAmountField->setSendAlwaysEvents(true); + mAmountField->setEnabled(false); + + // TRANSLATORS: buy dialog label + mAmountLabel = new Label(this, _("Amount:")); + mAmountLabel->adjustSize(); + + // TRANSLATORS: This is a narrow symbol used to denote 'increasing'. + // You may change this symbol if your language uses another. + mIncreaseButton = new Button(this, _("+"), "inc", this); + // TRANSLATORS: This is a narrow symbol used to denote 'decreasing'. + // You may change this symbol if your language uses another. + mDecreaseButton = new Button(this, _("-"), "dec", this); + // TRANSLATORS: buy dialog button + mBuyButton = new Button(this, mNpcId == -2 + ? _("Create") :_("Buy"), "buy", this); + // TRANSLATORS: buy dialog button + mQuitButton = new Button(this, _("Quit"), "quit", this); + // TRANSLATORS: buy dialog button + mAddMaxButton = new Button(this, _("Max"), "max", this); + + mDecreaseButton->adjustSize(); + mDecreaseButton->setWidth(mIncreaseButton->getWidth()); + + mIncreaseButton->setEnabled(false); + mDecreaseButton->setEnabled(false); + mBuyButton->setEnabled(false); + mSlider->setEnabled(false); + + mSlider->setActionEventId("slider"); + mSlider->addActionListener(this); + + mShopItemList->setDistributeMousePressed(false); + mShopItemList->setActionEventId("buy"); + mShopItemList->addActionListener(this); + mShopItemList->addSelectionListener(this); + + ContainerPlacer placer = getPlacer(0, 0); + placer(0, 0, mScrollArea, 9, 5).setPadding(3); + placer(0, 5, mDecreaseButton); + placer(1, 5, mSlider, 4); + placer(5, 5, mIncreaseButton); + placer(6, 5, mQuantityLabel, 2); + placer(8, 5, mAddMaxButton); + placer(0, 6, mAmountLabel, 2); + placer(2, 6, mAmountField, 2); + placer(0, 7, mMoneyLabel, 8); + if (mSortDropDown) + placer(0, 8, mSortDropDown, 2); + placer(7, 8, mBuyButton); + placer(8, 8, mQuitButton); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + + center(); + loadWindowState(); + enableVisibleSound(true); + + instances.push_back(this); + setVisible(true); +} + +BuyDialog::~BuyDialog() +{ + delete mShopItems; + mShopItems = nullptr; + + instances.remove(this); +} + +void BuyDialog::setMoney(const int amount) +{ + mMoney = amount; + mShopItemList->setPlayersMoney(amount); + + updateButtonsAndLabels(); +} + +void BuyDialog::reset() +{ + mShopItems->clear(); + mShopItemList->adjustSize(); + + // Reset previous selected items to prevent failing asserts + mShopItemList->setSelected(-1); + mSlider->setValue(0); + + setMoney(0); +} + +void BuyDialog::addItem(const int id, const unsigned char color, + const int amount, const int price) +{ + mShopItems->addItem(id, color, amount, price); + mShopItemList->adjustSize(); +} + +void BuyDialog::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "quit") + { + close(); + return; + } + else if (eventId == "sort") + { + if (mSortDropDown && mShopItems) + { + std::vector &items = mShopItems->items(); + switch (mSortDropDown->getSelected()) + { + case 1: + std::sort(items.begin(), items.end(), itemPriceBuySorter); + break; + case 2: + std::sort(items.begin(), items.end(), itemNameBuySorter); + break; + case 3: + std::sort(items.begin(), items.end(), itemIdBuySorter); + break; + case 4: + std::sort(items.begin(), items.end(), itemWeightBuySorter); + break; + case 5: + std::sort(items.begin(), items.end(), itemAmountBuySorter); + break; + case 6: + std::sort(items.begin(), items.end(), itemTypeBuySorter); + break; + case 0: + default: + break; + } + } + return; + } + + const int selectedItem = mShopItemList->getSelected(); + + // The following actions require a valid selection + if (selectedItem < 0 || selectedItem >= mShopItems->getNumberOfElements()) + return; + + if (eventId == "slider") + { + mAmountItems = static_cast(mSlider->getValue()); + mAmountField->setValue(mAmountItems); + updateButtonsAndLabels(); + } + else if (eventId == "inc" && mAmountItems < mMaxItems) + { + mAmountItems++; + mSlider->setValue(mAmountItems); + mAmountField->setValue(mAmountItems); + updateButtonsAndLabels(); + } + else if (eventId == "dec" && mAmountItems > 1) + { + mAmountItems--; + mSlider->setValue(mAmountItems); + mAmountField->setValue(mAmountItems); + updateButtonsAndLabels(); + } + else if (eventId == "max") + { + mAmountItems = mMaxItems; + mSlider->setValue(mAmountItems); + mAmountField->setValue(mAmountItems); + updateButtonsAndLabels(); + } + else if (eventId == "amount") + { + mAmountItems = mAmountField->getValue(); + mSlider->setValue(mAmountItems); + updateButtonsAndLabels(); + } + else if (eventId == "buy" && mAmountItems > 0 && mAmountItems <= mMaxItems) + { + if (mNpcId == -2) + { + const ShopItem *const item = mShopItems->at(selectedItem); + Net::getAdminHandler()->createItems(item->getId(), + mAmountItems, item->getColor()); + } + else if (mNpcId != -1) + { + const ShopItem *const item = mShopItems->at(selectedItem); + Net::getNpcHandler()->buyItem(mNpcId, item->getId(), + item->getColor(), mAmountItems); + + // Update money and adjust the max number of items + // that can be bought + mMaxItems -= mAmountItems; + setMoney(mMoney - + mAmountItems * mShopItems->at(selectedItem)->getPrice()); + + // Reset selection + mAmountItems = 1; + mSlider->setValue(1); + mSlider->setScale(1, mMaxItems); + } + else if (tradeWindow) + { + const ShopItem *const item = mShopItems->at(selectedItem); + if (item) + { + Net::getBuySellHandler()->sendBuyRequest(mNick, + item, mAmountItems); + if (tradeWindow) + { + tradeWindow->addAutoMoney(mNick, + item->getPrice() * mAmountItems); + } + } + } + } +} + +void BuyDialog::valueChanged(const gcn::SelectionEvent &event A_UNUSED) +{ + // Reset amount of items and update labels + mAmountItems = 1; + mSlider->setValue(1); + + updateButtonsAndLabels(); + mSlider->setScale(1, mMaxItems); + mAmountField->setRange(1, mMaxItems); + mAmountField->setValue(1); +} + +void BuyDialog::updateButtonsAndLabels() +{ + const int selectedItem = mShopItemList->getSelected(); + int price = 0; + + if (selectedItem > -1) + { + const ShopItem *const item = mShopItems->at(selectedItem); + if (item) + { + const int itemPrice = item->getPrice(); + + // Calculate how many the player can afford + if (mNpcId == -2) + mMaxItems = 100; + else if (itemPrice) + mMaxItems = mMoney / itemPrice; + else + mMaxItems = 1; + + if (item->getQuantity() > 0 && mMaxItems > item->getQuantity()) + mMaxItems = item->getQuantity(); + + if (mAmountItems > mMaxItems) + mAmountItems = mMaxItems; + + price = mAmountItems * itemPrice; + } + } + else + { + mMaxItems = 0; + mAmountItems = 0; + } + + mIncreaseButton->setEnabled(mAmountItems < mMaxItems); + mDecreaseButton->setEnabled(mAmountItems > 1); + mBuyButton->setEnabled(mAmountItems > 0); + mSlider->setEnabled(mMaxItems > 1); + mAmountField->setEnabled(mAmountItems > 0); + + mQuantityLabel->setCaption(strprintf("%d / %d", mAmountItems, mMaxItems)); + // TRANSLATORS: buy dialog label + mMoneyLabel->setCaption(strprintf(_("Price: %s / Total: %s"), + Units::formatCurrency(price).c_str(), + Units::formatCurrency(mMoney - price).c_str())); +} + +void BuyDialog::setVisible(bool visible) +{ + Window::setVisible(visible); + + if (visible && mShopItemList) + mShopItemList->requestFocus(); + else + scheduleDelete(); +} + +void BuyDialog::closeAll() +{ + FOR_EACH (DialogList::const_iterator, it, instances) + { + if (*it) + (*it)->close(); + } +} diff --git a/src/gui/windows/buydialog.h b/src/gui/windows/buydialog.h new file mode 100644 index 000000000..875184851 --- /dev/null +++ b/src/gui/windows/buydialog.h @@ -0,0 +1,163 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_BUYDIALOG_H +#define GUI_BUYDIALOG_H + +#include "gui/widgets/window.h" + +#include +#include + +class Button; +class DropDown; +class ShopItems; +class ShopListBox; +class SortListModelBuy; +class IntTextField; +class Label; +class ListBox; +class ScrollArea; +class Slider; + +/** + * The buy dialog. + * + * \ingroup Interface + */ +class BuyDialog final : public Window, + public gcn::ActionListener, + public gcn::SelectionListener +{ + public: + /** + * Constructor. + * + * @see Window::Window + */ + BuyDialog(); + + /** + * Constructor. + * + * @see Window::Window + */ + explicit BuyDialog(const int npcId); + + /** + * Constructor. + * + * @see Window::Window + */ + explicit BuyDialog(std::string nick); + + A_DELETE_COPY(BuyDialog) + + /** + * Destructor + */ + ~BuyDialog(); + + void init(); + + /** + * Resets the dialog, clearing shop inventory. + */ + void reset(); + + /** + * Sets the amount of available money. + */ + void setMoney(const int amount); + + /** + * Adds an item to the shop inventory. + */ + void addItem(const int id, const unsigned char color, + const int amount, const int price); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + /** + * Returns the number of items in the shop inventory. + */ + int getNumberOfElements() A_WARN_UNUSED; + + /** + * Updates the labels according to the selected item. + */ + void valueChanged(const gcn::SelectionEvent &event) override; + + /** + * Updates the state of buttons and labels. + */ + void updateButtonsAndLabels(); + + /** + * Sets the visibility of this window. + */ + void setVisible(bool visible); + + /** + * Returns true if any instances exist. + */ + static bool isActive() A_WARN_UNUSED + { return !instances.empty(); } + + /** + * Closes all instances. + */ + static void closeAll(); + + private: + typedef std::list DialogList; + static DialogList instances; + + int mNpcId; + + Button *mBuyButton; + Button *mQuitButton; + Button *mAddMaxButton; + Button *mIncreaseButton; + Button *mDecreaseButton; + ShopListBox *mShopItemList; + ScrollArea *mScrollArea; + Label *mMoneyLabel; + Label *mQuantityLabel; + Slider *mSlider; + Label *mAmountLabel; + IntTextField *mAmountField; + + ShopItems *mShopItems; + + int mMoney; + int mAmountItems; + int mMaxItems; + std::string mNick; + SortListModelBuy *mSortModel; + DropDown *mSortDropDown; +}; + +#endif // GUI_BUYDIALOG_H diff --git a/src/gui/windows/buyselldialog.cpp b/src/gui/windows/buyselldialog.cpp new file mode 100644 index 000000000..d26b0ceb8 --- /dev/null +++ b/src/gui/windows/buyselldialog.cpp @@ -0,0 +1,150 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/buyselldialog.h" + +#include "net/buysellhandler.h" +#include "net/net.h" +#include "net/npchandler.h" + +#include "gui/widgets/button.h" + +#include "utils/gettext.h" + +#include "debug.h" + +BuySellDialog::DialogList BuySellDialog::dialogInstances; + +BuySellDialog::BuySellDialog(const int npcId) : + // TRANSLATORS: shop window name + Window(_("Shop"), false, nullptr, "buysell.xml"), + gcn::ActionListener(), + mNpcId(npcId), + mNick(""), + mBuyButton(nullptr) +{ + init(); +} + +BuySellDialog::BuySellDialog(const std::string &nick) : + // TRANSLATORS: shop window name + Window(_("Shop"), false, nullptr, "buysell.xml"), + gcn::ActionListener(), + mNpcId(-1), + mNick(nick), + mBuyButton(nullptr) +{ + init(); +} + +void BuySellDialog::init() +{ + setWindowName("BuySell"); + setCloseButton(true); + + static const char *buttonNames[] = + { + // TRANSLATORS: shop window button + N_("Buy"), + // TRANSLATORS: shop window button + N_("Sell"), + // TRANSLATORS: shop window button + N_("Cancel"), + nullptr + }; + const int buttonPadding = getOption("buttonpadding", 10); + int x = buttonPadding; + const int y = buttonPadding; + + for (const char *const *curBtn = buttonNames; *curBtn; curBtn++) + { + Button *const btn = new Button(this, gettext(*curBtn), *curBtn, this); + if (!mBuyButton) + mBuyButton = btn; // For focus request + btn->setPosition(x, y); + add(btn); + x += btn->getWidth() + buttonPadding; + } + if (mBuyButton) + { + mBuyButton->requestFocus(); + setContentSize(x, 2 * y + mBuyButton->getHeight()); + } + + center(); + setDefaultSize(); + loadWindowState(); + enableVisibleSound(true); + + dialogInstances.push_back(this); + setVisible(true); +} + +BuySellDialog::~BuySellDialog() +{ + dialogInstances.remove(this); +} + +void BuySellDialog::setVisible(bool visible) +{ + Window::setVisible(visible); + + if (visible) + { + if (mBuyButton) + mBuyButton->requestFocus(); + } + else + { + scheduleDelete(); + } +} + +void BuySellDialog::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "Buy") + { + if (mNpcId != -1) + Net::getNpcHandler()->buy(mNpcId); + else + Net::getBuySellHandler()->requestSellList(mNick); + } + else if (eventId == "Sell") + { + if (mNpcId != -1) + Net::getNpcHandler()->sell(mNpcId); + else + Net::getBuySellHandler()->requestBuyList(mNick); + } + + close(); +} + +void BuySellDialog::closeAll() +{ + FOR_EACH (DialogList::const_iterator, it, dialogInstances) + { + if (*it) + (*it)->close(); + } +} diff --git a/src/gui/windows/buyselldialog.h b/src/gui/windows/buyselldialog.h new file mode 100644 index 000000000..193364ff8 --- /dev/null +++ b/src/gui/windows/buyselldialog.h @@ -0,0 +1,83 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_BUYSELLDIALOG_H +#define GUI_BUYSELLDIALOG_H + +#include "gui/widgets/window.h" + +#include + +class Button; + +/** + * A dialog to choose between buying or selling at a shop. + * + * \ingroup Interface + */ +class BuySellDialog final : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor. The action listener passed will receive "sell", "buy" + * or "cancel" events when the respective buttons are pressed. + * + * @see Window::Window + */ + explicit BuySellDialog(const int npcId); + + explicit BuySellDialog(const std::string &nick); + + A_DELETE_COPY(BuySellDialog) + + ~BuySellDialog(); + + void init(); + + void setVisible(bool visible); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + /** + * Returns true if any instances exist. + */ + static bool isActive() A_WARN_UNUSED + { return !dialogInstances.empty(); } + + /** + * Closes all instances. + */ + static void closeAll(); + + private: + typedef std::list DialogList; + static DialogList dialogInstances; + + int mNpcId; + std::string mNick; + Button *mBuyButton; +}; + +#endif // GUI_BUYSELLDIALOG_H diff --git a/src/gui/windows/changeemaildialog.cpp b/src/gui/windows/changeemaildialog.cpp new file mode 100644 index 000000000..61ff7ef3d --- /dev/null +++ b/src/gui/windows/changeemaildialog.cpp @@ -0,0 +1,181 @@ +/* + * The ManaPlus Client + * Copyright (C) 2008-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/changeemaildialog.h" + +#include "client.h" + +#include "gui/windows/registerdialog.h" +#include "gui/windows/okdialog.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/label.h" +#include "gui/widgets/textfield.h" + +#include "net/logindata.h" +#include "net/loginhandler.h" +#include "net/net.h" + +#include "utils/gettext.h" + +#include +#include + +#include "debug.h" + +ChangeEmailDialog::ChangeEmailDialog(LoginData *const data): + // TRANSLATORS: change email dialog header + Window(_("Change Email Address"), true, nullptr, "changeemail.xml"), + gcn::ActionListener(), + mFirstEmailField(new TextField(this)), + mSecondEmailField(new TextField(this)), + // TRANSLATORS: button in change email dialog + mChangeEmailButton(new Button(this, _("Change Email Address"), + "change_email", this)), + // TRANSLATORS: button in change email dialog + mCancelButton(new Button(this, _("Cancel"), "cancel", this)), + mWrongDataNoticeListener(new WrongDataNoticeListener), + mLoginData(data) +{ + // TRANSLATORS: label in change email dialog + Label *const accountLabel = new Label(this, strprintf(_("Account: %s"), + mLoginData->username.c_str())); + Label *const newEmailLabel = new Label(this, + // TRANSLATORS: label in change email dialog + _("Type new email address twice:")); + + const int width = 200; + const int height = 130; + setContentSize(width, height); + + accountLabel->setPosition(5, 5); + accountLabel->setWidth(130); + + newEmailLabel->setPosition( + 5, accountLabel->getY() + accountLabel->getHeight() + 7); + newEmailLabel->setWidth(width - 5); + + mFirstEmailField->setPosition( + 5, newEmailLabel->getY() + newEmailLabel->getHeight() + 7); + mFirstEmailField->setWidth(130); + + mSecondEmailField->setPosition( + 5, mFirstEmailField->getY() + mFirstEmailField->getHeight() + 7); + mSecondEmailField->setWidth(130); + + mCancelButton->setPosition( + width - 5 - mCancelButton->getWidth(), + height - 5 - mCancelButton->getHeight()); + mChangeEmailButton->setPosition( + mCancelButton->getX() - 5 - mChangeEmailButton->getWidth(), + mCancelButton->getY()); + + add(accountLabel); + add(newEmailLabel); + add(mFirstEmailField); + add(mSecondEmailField); + add(mChangeEmailButton); + add(mCancelButton); + + center(); + setVisible(true); + mFirstEmailField->requestFocus(); + + mFirstEmailField->setActionEventId("change_email"); + mSecondEmailField->setActionEventId("change_email"); +} + +ChangeEmailDialog::~ChangeEmailDialog() +{ + delete mWrongDataNoticeListener; + mWrongDataNoticeListener = nullptr; +} + +void ChangeEmailDialog::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "cancel") + { + client->setState(STATE_CHAR_SELECT); + } + else if (eventId == "change_email") + { + const std::string username = mLoginData->username.c_str(); + const std::string newFirstEmail = mFirstEmailField->getText(); + const std::string newSecondEmail = mSecondEmailField->getText(); + logger->log("ChangeEmailDialog::Email change, Username is %s", + username.c_str()); + + std::stringstream errorMsg; + int error = 0; + + const unsigned int min = Net::getLoginHandler() + ->getMinPasswordLength(); + const unsigned int max = Net::getLoginHandler() + ->getMaxPasswordLength(); + + if (newFirstEmail.length() < min) + { + // First email address too short + // TRANSLATORS: change email error + errorMsg << strprintf(_("The new email address needs to be at " + "least %u characters long."), min); + error = 1; + } + else if (newFirstEmail.length() > max) + { + // First email address too long + // TRANSLATORS: change email error + errorMsg << strprintf(_("The new email address needs to be " + "less than %u characters long."), max); + error = 1; + } + else if (newFirstEmail != newSecondEmail) + { + // Second Pass mismatch + // TRANSLATORS: change email error + errorMsg << _("The email address entries mismatch."); + error = 2; + } + + if (error > 0) + { + if (error == 1) + mWrongDataNoticeListener->setTarget(this->mFirstEmailField); + else if (error == 2) + mWrongDataNoticeListener->setTarget(this->mSecondEmailField); + + // TRANSLATORS: change email error header + OkDialog *const dlg = new OkDialog(_("Error"), + errorMsg.str(), DIALOG_ERROR); + dlg->addActionListener(mWrongDataNoticeListener); + } + else + { + // No errors detected, change account password. + mChangeEmailButton->setEnabled(false); + // Set the new email address + mLoginData->email = newFirstEmail; + client->setState(STATE_CHANGEEMAIL_ATTEMPT); + } + } +} diff --git a/src/gui/windows/changeemaildialog.h b/src/gui/windows/changeemaildialog.h new file mode 100644 index 000000000..e61ac8bc5 --- /dev/null +++ b/src/gui/windows/changeemaildialog.h @@ -0,0 +1,80 @@ +/* + * The ManaPlus Client + * Copyright (C) 2008-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_CHANGEEMAILDIALOG_H +#define GUI_CHANGEEMAILDIALOG_H + +#include "gui/widgets/window.h" + +#include + +class Button; +class LoginData; +class TextField; +class WrongDataNoticeListener; + +/** + * The Change email dialog. + * + * \ingroup Interface + */ +class ChangeEmailDialog final : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor. + * + * @see Window::Window + */ + explicit ChangeEmailDialog(LoginData *const data); + + A_DELETE_COPY(ChangeEmailDialog) + + /** + * Destructor. + */ + ~ChangeEmailDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + /** + * This is used to pass the pointer to where the new email should be + * put when the dialog finishes. + */ + static void setEmail(std::string *email); + + private: + TextField *mFirstEmailField; + TextField *mSecondEmailField; + + Button *mChangeEmailButton; + Button *mCancelButton; + + WrongDataNoticeListener *mWrongDataNoticeListener; + + LoginData *mLoginData; +}; + +#endif // GUI_CHANGEEMAILDIALOG_H diff --git a/src/gui/windows/changepassworddialog.cpp b/src/gui/windows/changepassworddialog.cpp new file mode 100644 index 000000000..365ee19a8 --- /dev/null +++ b/src/gui/windows/changepassworddialog.cpp @@ -0,0 +1,172 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/changepassworddialog.h" + +#include "client.h" + +#include "gui/windows/registerdialog.h" +#include "gui/windows/okdialog.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/passwordfield.h" +#include "gui/widgets/label.h" +#include "gui/widgets/layout.h" + +#include "net/logindata.h" +#include "net/loginhandler.h" +#include "net/net.h" + +#include "utils/gettext.h" + +#include +#include + +#include "debug.h" + +ChangePasswordDialog::ChangePasswordDialog(LoginData *const data): + // TRANSLATORS: change password window name + Window(_("Change Password"), true, nullptr, "changepassword.xml"), + gcn::ActionListener(), + mOldPassField(new PasswordField(this)), + mFirstPassField(new PasswordField(this)), + mSecondPassField(new PasswordField(this)), + // TRANSLATORS: change password dialog button + mChangePassButton(new Button(this, _("Change Password"), + "change_password", this)), + // TRANSLATORS: change password dialog button + mCancelButton(new Button(this, _("Cancel"), "cancel", this)), + mWrongDataNoticeListener(new WrongDataNoticeListener), + mLoginData(data) +{ + Label *const accountLabel = new Label(this, + // TRANSLATORS: change password dialog label + strprintf(_("Account: %s"), mLoginData->username.c_str())); + + place(0, 0, accountLabel, 3); + // TRANSLATORS: change password dialog label + place(0, 1, new Label(this, _("Password:")), 3); + place(0, 2, mOldPassField, 3).setPadding(1); + // TRANSLATORS: change password dialog label + place(0, 3, new Label(this, _("Type new password twice:")), 3); + place(0, 4, mFirstPassField, 3).setPadding(1); + place(0, 5, mSecondPassField, 3).setPadding(1); + place(1, 6, mCancelButton); + place(2, 6, mChangePassButton); + reflowLayout(200); + + center(); + setVisible(true); + mOldPassField->requestFocus(); + + mOldPassField->setActionEventId("change_password"); + mFirstPassField->setActionEventId("change_password"); + mSecondPassField->setActionEventId("change_password"); +} + +ChangePasswordDialog::~ChangePasswordDialog() +{ + delete mWrongDataNoticeListener; + mWrongDataNoticeListener = nullptr; +} + +void ChangePasswordDialog::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "cancel") + { + client->setState(STATE_CHAR_SELECT); + } + else if (eventId == "change_password") + { + const std::string username = mLoginData->username.c_str(); + const std::string oldPassword = mOldPassField->getText(); + const std::string newFirstPass = mFirstPassField->getText(); + const std::string newSecondPass = mSecondPassField->getText(); + logger->log("ChangePasswordDialog::Password change, Username is %s", + username.c_str()); + + std::stringstream errorMsg; + int error = 0; + + const unsigned int min = Net::getLoginHandler() + ->getMinPasswordLength(); + const unsigned int max = Net::getLoginHandler() + ->getMaxPasswordLength(); + + // Check old Password + if (oldPassword.empty()) + { + // No old password + // TRANSLATORS: change password error + errorMsg << _("Enter the old password first."); + error = 1; + } + else if (newFirstPass.length() < min) + { + // First password too short + // TRANSLATORS: change password error + errorMsg << strprintf(_("The new password needs to be at least" + " %u characters long."), min); + error = 2; + } + else if (newFirstPass.length() > max) + { + // First password too long + // TRANSLATORS: change password error + errorMsg << strprintf(_("The new password needs to be less " + "than %u characters long."), max); + error = 2; + } + else if (newFirstPass != newSecondPass) + { + // Second Pass mismatch + // TRANSLATORS: change password error + errorMsg << _("The new password entries mismatch."); + error = 3; + } + + if (error > 0) + { + if (error == 1) + mWrongDataNoticeListener->setTarget(this->mOldPassField); + else if (error == 2) + mWrongDataNoticeListener->setTarget(this->mFirstPassField); + else if (error == 3) + mWrongDataNoticeListener->setTarget(this->mSecondPassField); + + // TRANSLATORS: change password error header + OkDialog *const dlg = new OkDialog(_("Error"), + errorMsg.str(), DIALOG_ERROR); + dlg->addActionListener(mWrongDataNoticeListener); + } + else + { + // No errors detected, change account password. + mChangePassButton->setEnabled(false); + // Set the new password + mLoginData->password = oldPassword; + mLoginData->newPassword = newFirstPass; + client->setState(STATE_CHANGEPASSWORD_ATTEMPT); + } + } +} diff --git a/src/gui/windows/changepassworddialog.h b/src/gui/windows/changepassworddialog.h new file mode 100644 index 000000000..fd70348a6 --- /dev/null +++ b/src/gui/windows/changepassworddialog.h @@ -0,0 +1,75 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_CHANGEPASSWORDDIALOG_H +#define GUI_CHANGEPASSWORDDIALOG_H + +#include "gui/widgets/window.h" + +#include + +class Button; +class LoginData; +class TextField; +class WrongDataNoticeListener; + +/** + * The Change password dialog. + * + * \ingroup Interface + */ +class ChangePasswordDialog final : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor + * + * @see Window::Window + */ + explicit ChangePasswordDialog(LoginData *const data); + + A_DELETE_COPY(ChangePasswordDialog) + + /** + * Destructor + */ + ~ChangePasswordDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + private: + TextField *mOldPassField; + TextField *mFirstPassField; + TextField *mSecondPassField; + + Button *mChangePassButton; + Button *mCancelButton; + + WrongDataNoticeListener *mWrongDataNoticeListener; + + LoginData *mLoginData; +}; + +#endif // GUI_CHANGEPASSWORDDIALOG_H diff --git a/src/gui/windows/charcreatedialog.cpp b/src/gui/windows/charcreatedialog.cpp new file mode 100644 index 000000000..53f1a5bce --- /dev/null +++ b/src/gui/windows/charcreatedialog.cpp @@ -0,0 +1,698 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/charcreatedialog.h" + +#include "main.h" + +#include "input/keydata.h" +#include "input/keyevent.h" + +#include "gui/windows/okdialog.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/label.h" +#include "gui/widgets/playerbox.h" +#include "gui/widgets/radiobutton.h" +#include "gui/widgets/slider.h" +#include "gui/widgets/textfield.h" + +#include "net/net.h" + +#include "resources/chardb.h" +#include "resources/colordb.h" +#include "resources/itemdb.h" +#include "resources/iteminfo.h" + +#include "utils/gettext.h" + +#include "debug.h" + +extern int serverVersion; + +static const Being::Action actions[] = +{ + Being::STAND, Being::SIT, Being::MOVE, Being::ATTACK, Being::DEAD +}; + +static const uint8_t directions[] = +{ + Being::DOWN, Being::RIGHT, Being::UP, Being::LEFT +}; + +CharCreateDialog::CharCreateDialog(CharSelectDialog *const parent, + const int slot) : + // TRANSLATORS: char create dialog name + Window(_("New Character"), true, parent, "charcreate.xml"), + gcn::ActionListener(), + gcn::KeyListener(), + mCharSelectDialog(parent), + mNameField(new TextField(this, "")), + // TRANSLATORS: char create dialog label + mNameLabel(new Label(this, _("Name:"))), + // TRANSLATORS: This is a narrow symbol used to denote 'next'. + // You may change this symbol if your language uses another. + // TRANSLATORS: char create dialog button + mNextHairColorButton(new Button(this, _(">"), "nextcolor", this)), + // TRANSLATORS: This is a narrow symbol used to denote 'previous'. + // You may change this symbol if your language uses another. + // TRANSLATORS: char create dialog button + mPrevHairColorButton(new Button(this, _("<"), "prevcolor", this)), + // TRANSLATORS: char create dialog label + mHairColorLabel(new Label(this, _("Hair color:"))), + mHairColorNameLabel(new Label(this, "")), + // TRANSLATORS: char create dialog button + mNextHairStyleButton(new Button(this, _(">"), "nextstyle", this)), + // TRANSLATORS: char create dialog button + mPrevHairStyleButton(new Button(this, _("<"), "prevstyle", this)), + // TRANSLATORS: char create dialog label + mHairStyleLabel(new Label(this, _("Hair style:"))), + mHairStyleNameLabel(new Label(this, "")), + mNextRaceButton(nullptr), + mPrevRaceButton(nullptr), + mRaceLabel(nullptr), + mRaceNameLabel(nullptr), + mNextLookButton(nullptr), + mPrevLookButton(nullptr), + mLookLabel(nullptr), + mLookNameLabel(nullptr), + // TRANSLATORS: char create dialog button + mActionButton(new Button(this, _("^"), "action", this)), + // TRANSLATORS: char create dialog button + mRotateButton(new Button(this, _(">"), "rotate", this)), + // TRANSLATORS: char create dialog button + mMale(new RadioButton(this, _("Male"), "gender")), + // TRANSLATORS: char create dialog button + mFemale(new RadioButton(this, _("Female"), "gender")), + // TRANSLATORS: char create dialog button + mOther(new RadioButton(this, _("Other"), "gender")), + mAttributeSlider(), + mAttributeLabel(), + mAttributeValue(), + mAttributesLeft(new Label(this, + // TRANSLATORS: char create dialog label + strprintf(_("Please distribute %d points"), 99))), + mMaxPoints(0), + mUsedPoints(0), + // TRANSLATORS: char create dialog button + mCreateButton(new Button(this, _("Create"), "create", this)), + // TRANSLATORS: char create dialog button + mCancelButton(new Button(this, _("Cancel"), "cancel", this)), + mRace(0), + mLook(0), + mMinLook(CharDB::getMinLook()), + mMaxLook(CharDB::getMaxLook()), + mPlayer(new Being(0, ActorSprite::PLAYER, static_cast(mRace), + nullptr)), + mPlayerBox(new PlayerBox(mPlayer, "charcreate_playerbox.xml", + "charcreate_selectedplayerbox.xml")), + mHairStyle(0), + mHairColor(0), + mSlot(slot), + maxHairColor(CharDB::getMaxHairColor()), + minHairColor(CharDB::getMinHairColor()), + maxHairStyle(CharDB::getMaxHairStyle()), + minHairStyle(CharDB::getMinHairStyle()), + mAction(0), + mDirection(0) +{ + setStickyButtonLock(true); + setSticky(true); + setWindowName("NewCharacter"); + + mPlayer->setGender(GENDER_MALE); + const std::vector &items = CharDB::getDefaultItems(); + int i = 1; + for (std::vector::const_iterator it = items.begin(), + it_end = items.end(); + it != it_end; ++ it, i ++) + { + mPlayer->setSprite(i, *it); + } + + if (!maxHairColor) + maxHairColor = ColorDB::getHairSize(); + if (!maxHairStyle) + maxHairStyle = mPlayer->getNumOfHairstyles(); + + if (maxHairStyle) + mHairStyle = (rand() % maxHairStyle) + minHairStyle; + else + mHairStyle = 0; + if (maxHairColor) + mHairColor = (rand() % maxHairColor) + minHairColor; + else + mHairColor = 0; + + mNameField->setMaximum(24); + + if (serverVersion >= 2) + { + // TRANSLATORS: char create dialog button + mNextRaceButton = new Button(this, _(">"), "nextrace", this); + // TRANSLATORS: char create dialog button + mPrevRaceButton = new Button(this, _("<"), "prevrace", this); + // TRANSLATORS: char create dialog label + mRaceLabel = new Label(this, _("Race:")); + mRaceNameLabel = new Label(this, ""); + } + if (serverVersion >= 9 && mMinLook < mMaxLook) + { + // TRANSLATORS: char create dialog button + mNextLookButton = new Button(this, _(">"), "nextlook", this); + // TRANSLATORS: char create dialog button + mPrevLookButton = new Button(this, _("<"), "prevlook", this); + // TRANSLATORS: char create dialog label + mLookLabel = new Label(this, _("Look:")); + mLookNameLabel = new Label(this, ""); + } + + // Default to a Male character + mMale->setSelected(true); + + mMale->setActionEventId("gender"); + mFemale->setActionEventId("gender"); + mOther->setActionEventId("gender"); + + mMale->addActionListener(this); + mFemale->addActionListener(this); + mOther->addActionListener(this); + + mPlayerBox->setWidth(74); + + mNameField->setActionEventId("create"); + mNameField->addActionListener(this); + + const int w = 480; + const int h = 350; + + setContentSize(w, h); + mPlayerBox->setDimension(gcn::Rectangle(360, 0, 110, 90)); + mActionButton->setPosition(385, 100); + mRotateButton->setPosition(415, 100); + + mNameLabel->setPosition(5, 2); + mNameField->setDimension( + gcn::Rectangle(60, 2, 300, mNameField->getHeight())); + + const int leftX = 120; + const int rightX = 300; + const int labelX = 5; + const int nameX = 145; + int y = 30; + mPrevHairColorButton->setPosition(leftX, y); + mNextHairColorButton->setPosition(rightX, y); + y += 5; + mHairColorLabel->setPosition(labelX, y); + mHairColorNameLabel->setPosition(nameX, y); + y += 24; + mPrevHairStyleButton->setPosition(leftX, y); + mNextHairStyleButton->setPosition(rightX, y); + y += 5; + mHairStyleLabel->setPosition(labelX, y); + mHairStyleNameLabel->setPosition(nameX, y); + + if (serverVersion >= 9 && mMinLook < mMaxLook) + { + y += 24; + mPrevLookButton->setPosition(leftX, y); + mNextLookButton->setPosition(rightX, y); + y += 5; + mLookLabel->setPosition(labelX, y); + mLookNameLabel->setPosition(nameX, y); // 93 + } + if (serverVersion >= 2) + { + y += 24; + mPrevRaceButton->setPosition(leftX, y); + mNextRaceButton->setPosition(rightX, y); + y += 5; + mRaceLabel->setPosition(labelX, y); + mRaceNameLabel->setPosition(nameX, y); + } + + updateSliders(); + setButtonsPosition(w, h); + + mMale->setPosition(30, 120); + mFemale->setPosition(100, 120); + mOther->setPosition(170, 120); + + add(mPlayerBox); + add(mNameField); + add(mNameLabel); + add(mNextHairColorButton); + add(mPrevHairColorButton); + add(mHairColorLabel); + add(mHairColorNameLabel); + add(mNextHairStyleButton); + add(mPrevHairStyleButton); + add(mHairStyleLabel); + add(mHairStyleNameLabel); + add(mActionButton); + add(mRotateButton); + + if (serverVersion >= 9 && mMinLook < mMaxLook) + { + add(mNextLookButton); + add(mPrevLookButton); + add(mLookLabel); + add(mLookNameLabel); + } + + if (serverVersion >= 2) + { + add(mNextRaceButton); + add(mPrevRaceButton); + add(mRaceLabel); + add(mRaceNameLabel); + } + + add(mAttributesLeft); + add(mCreateButton); + add(mCancelButton); + + add(mMale); + add(mFemale); + add(mOther); + + center(); + setVisible(true); + mNameField->requestFocus(); + + updateHair(); + if (serverVersion >= 2) + updateRace(); + if (serverVersion >= 9 && mMinLook < mMaxLook) + updateLook(); + updatePlayer(); + + addKeyListener(this); +} + +CharCreateDialog::~CharCreateDialog() +{ + delete mPlayer; + mPlayer = nullptr; + + if (Net::getCharServerHandler()) + Net::getCharServerHandler()->setCharCreateDialog(nullptr); +} + +void CharCreateDialog::action(const gcn::ActionEvent &event) +{ + const std::string id = event.getId(); + if (id == "create") + { + if ( +#ifdef MANASERV_SUPPORT + Net::getNetworkType() == ServerInfo::MANASERV || +#endif + getName().length() >= 4) + { + // Attempt to create the character + mCreateButton->setEnabled(false); + + std::vector atts; + for (size_t i = 0, sz = mAttributeSlider.size(); i < sz; i++) + { + atts.push_back(static_cast( + mAttributeSlider[i]->getValue())); + } + +#ifdef MANASERV_SUPPORT + int characterSlot = mSlot; + // On Manaserv, the slots start at 1, so we offset them. + if (Net::getNetworkType() == ServerInfo::MANASERV) + ++characterSlot; +#else + const int characterSlot = mSlot; +#endif + + Net::getCharServerHandler()->newCharacter(getName(), characterSlot, + mFemale->isSelected(), mHairStyle, mHairColor, + static_cast(mRace), mLook, atts); + } + else + { + // TRANSLATORS: char creation error + new OkDialog(_("Error"), + // TRANSLATORS: char creation error + _("Your name needs to be at least 4 characters."), + DIALOG_ERROR, true, this); + } + } + else if (id == "cancel") + { + scheduleDelete(); + } + else if (id == "nextcolor") + { + mHairColor ++; + updateHair(); + } + else if (id == "prevcolor") + { + mHairColor --; + updateHair(); + } + else if (id == "nextstyle") + { + mHairStyle ++; + updateHair(); + } + else if (id == "prevstyle") + { + mHairStyle --; + updateHair(); + } + else if (id == "nextrace") + { + mRace ++; + updateRace(); + } + else if (id == "prevrace") + { + mRace --; + updateRace(); + } + else if (id == "nextlook") + { + mLook ++; + updateLook(); + } + else if (id == "prevlook") + { + mLook --; + updateLook(); + } + else if (id == "statslider") + { + updateSliders(); + } + else if (id == "gender") + { + if (mMale->isSelected()) + mPlayer->setGender(GENDER_MALE); + else + mPlayer->setGender(GENDER_FEMALE); + } + else if (id == "action") + { + mAction ++; + if (mAction >= 5) + mAction = 0; + updatePlayer(); + } + else if (id == "rotate") + { + mDirection ++; + if (mDirection >= 4) + mDirection = 0; + updatePlayer(); + } +} + +std::string CharCreateDialog::getName() const +{ + std::string name = mNameField->getText(); + trim(name); + return name; +} + +void CharCreateDialog::updateSliders() +{ + for (size_t i = 0, sz = mAttributeSlider.size(); i < sz; i++) + { + // Update captions + mAttributeValue[i]->setCaption( + toString(static_cast(mAttributeSlider[i]->getValue()))); + mAttributeValue[i]->adjustSize(); + } + + // Update distributed points + const int pointsLeft = mMaxPoints - getDistributedPoints(); + if (pointsLeft == 0) + { + // TRANSLATORS: char create dialog label + mAttributesLeft->setCaption(_("Character stats OK")); + mCreateButton->setEnabled(true); + } + else + { + mCreateButton->setEnabled(false); + if (pointsLeft > 0) + { + mAttributesLeft->setCaption( + // TRANSLATORS: char create dialog label + strprintf(_("Please distribute %d points"), pointsLeft)); + } + else + { + mAttributesLeft->setCaption( + // TRANSLATORS: char create dialog label + strprintf(_("Please remove %d points"), -pointsLeft)); + } + } + + mAttributesLeft->adjustSize(); +} + +void CharCreateDialog::unlock() +{ + mCreateButton->setEnabled(true); +} + +int CharCreateDialog::getDistributedPoints() const +{ + int points = 0; + + for (size_t i = 0, sz = mAttributeSlider.size(); i < sz; i++) + points += static_cast(mAttributeSlider[i]->getValue()); + return points; +} + +void CharCreateDialog::setAttributes(const StringVect &labels, + const int available, + const int min, const int max) +{ + mMaxPoints = available; + + for (unsigned i = 0; i < mAttributeLabel.size(); i++) + { + remove(mAttributeLabel[i]); + delete mAttributeLabel[i]; + mAttributeLabel[i] = nullptr; + remove(mAttributeSlider[i]); + delete mAttributeSlider[i]; + mAttributeSlider[i] = nullptr; + remove(mAttributeValue[i]); + delete mAttributeValue[i]; + mAttributeValue[i] = nullptr; + } + + mAttributeLabel.resize(labels.size()); + mAttributeSlider.resize(labels.size()); + mAttributeValue.resize(labels.size()); + + const int w = 480; + const int h = 350; + const int y = 118 + 29; + + for (unsigned i = 0, sz = static_cast(labels.size()); + i < sz; i++) + { + mAttributeLabel[i] = new Label(this, labels[i]); + mAttributeLabel[i]->setWidth(70); + mAttributeLabel[i]->setPosition(5, y + i * 24); + mAttributeLabel[i]->adjustSize(); + add(mAttributeLabel[i]); + + mAttributeSlider[i] = new Slider(min, max); + mAttributeSlider[i]->setDimension(gcn::Rectangle(140, y + i * 24, + 150, 12)); + mAttributeSlider[i]->setActionEventId("statslider"); + mAttributeSlider[i]->addActionListener(this); + add(mAttributeSlider[i]); + + mAttributeValue[i] = new Label(this, toString(min)); + mAttributeValue[i]->setPosition(295, y + i * 24); + add(mAttributeValue[i]); + } + + updateSliders(); + setButtonsPosition(w, h); +} + +void CharCreateDialog::setFixedGender(const bool fixed, const Gender gender) +{ + if (gender == GENDER_FEMALE) + { + mFemale->setSelected(true); + mMale->setSelected(false); + mOther->setSelected(false); + } + else if (gender == GENDER_MALE) + { + mFemale->setSelected(false); + mMale->setSelected(true); + mOther->setSelected(false); + } + else + { + mFemale->setSelected(false); + mMale->setSelected(false); + mOther->setSelected(true); + } + + mPlayer->setGender(gender); + + if (fixed) + { + mMale->setVisible(false); + mFemale->setVisible(false); + mOther->setVisible(false); + } +} + +void CharCreateDialog::updateHair() +{ + if (mHairStyle <= 0) + mHairStyle = Being::getNumOfHairstyles() - 1; + else + mHairStyle %= Being::getNumOfHairstyles(); + if (mHairStyle < static_cast(minHairStyle) + || mHairStyle > static_cast(maxHairStyle)) + { + mHairStyle = minHairStyle; + } + const ItemInfo &item = ItemDB::get(-mHairStyle); + mHairStyleNameLabel->setCaption(item.getName()); + mHairStyleNameLabel->adjustSize(); + + if (ColorDB::getHairSize()) + mHairColor %= ColorDB::getHairSize(); + else + mHairColor = 0; + if (mHairColor < 0) + mHairColor += ColorDB::getHairSize(); + if (mHairColor < static_cast(minHairColor) + || mHairColor > static_cast(maxHairColor)) + { + mHairColor = minHairColor; + } + mHairColorNameLabel->setCaption(ColorDB::getHairColorName(mHairColor)); + mHairColorNameLabel->adjustSize(); + + mPlayer->setSprite(Net::getCharServerHandler()->hairSprite(), + mHairStyle * -1, item.getDyeColorsString(mHairColor)); +} + +void CharCreateDialog::updateRace() +{ + if (mRace < 0) + mRace = Being::getNumOfRaces() - 1; + else if (mRace >= Being::getNumOfRaces()) + mRace = 0; + + updateLook(); +} + +void CharCreateDialog::updateLook() +{ + const ItemInfo &item = ItemDB::get(-100 - mRace); + const int sz = item.getColorsSize(); + if (sz > 0 && serverVersion >= 9) + { + if (mLook < 0) + mLook = sz - 1; + if (mLook > mMaxLook) + mLook = mMinLook; + if (mLook >= sz) + mLook = mMinLook; + } + else + { + mLook = 0; + } + mPlayer->setSubtype(static_cast(mRace), mLook); + if (mRaceNameLabel) + { + mRaceNameLabel->setCaption(item.getName()); + mRaceNameLabel->adjustSize(); + } + if (mLookNameLabel) + { + mLookNameLabel->setCaption(item.getColorName(mLook)); + mLookNameLabel->adjustSize(); + } +} + +void CharCreateDialog::logic() +{ + if (mPlayer) + mPlayer->logic(); +} + +void CharCreateDialog::updatePlayer() +{ + if (mPlayer) + { + mPlayer->setDirection(directions[mDirection]); + mPlayer->setAction(actions[mAction]); + } +} + +void CharCreateDialog::keyPressed(gcn::KeyEvent &keyEvent) +{ + const int actionId = static_cast(&keyEvent)->getActionId(); + switch (actionId) + { + case Input::KEY_GUI_CANCEL: + keyEvent.consume(); + action(gcn::ActionEvent(mCancelButton, + mCancelButton->getActionEventId())); + break; + + default: + break; + } +} + +void CharCreateDialog::setButtonsPosition(const int w, const int h) +{ + if (mainGraphics->getHeight() < 480) + { + mCreateButton->setPosition(340, 150); + mCancelButton->setPosition(340, 160 + mCreateButton->getHeight()); + } + else + { + mCancelButton->setPosition( + w / 2, + h - 5 - mCancelButton->getHeight()); + mCreateButton->setPosition( + mCancelButton->getX() - 5 - mCreateButton->getWidth(), + h - 5 - mCancelButton->getHeight()); + } + mAttributesLeft->setPosition(15, 260 + 29); +} diff --git a/src/gui/windows/charcreatedialog.h b/src/gui/windows/charcreatedialog.h new file mode 100644 index 000000000..7bb96284e --- /dev/null +++ b/src/gui/windows/charcreatedialog.h @@ -0,0 +1,165 @@ +/* + * The ManaPlus Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_CHARCREATEDIALOG_H +#define GUI_CHARCREATEDIALOG_H + +#include "being/being.h" + +#include "gui/windows/charselectdialog.h" + +#include +#include + +class Label; +class PlayerBox; +class RadioButton; +class Slider; +class TextField; + +/** + * Character creation dialog. + * + * \ingroup Interface + */ +class CharCreateDialog final : public Window, + public gcn::ActionListener, + public gcn::KeyListener +{ + public: + /** + * Constructor. + */ + CharCreateDialog(CharSelectDialog *const parent, const int slot); + + A_DELETE_COPY(CharCreateDialog) + + /** + * Destructor. + */ + ~CharCreateDialog(); + + void action(const gcn::ActionEvent &event) override; + + /** + * Unlocks the dialog, enabling the create character button again. + */ + void unlock(); + + void setAttributes(const StringVect &labels, + const int available, + const int min, const int max); + + void setFixedGender(const bool fixed, + const Gender gender = GENDER_FEMALE); + + void logic() override; + + void updatePlayer(); + + void keyPressed(gcn::KeyEvent &keyEvent) override; + + private: + int getDistributedPoints() const A_WARN_UNUSED; + + void updateSliders(); + + void setButtonsPosition(const int w, const int h); + + /** + * Returns the name of the character to create. + */ + std::string getName() const A_WARN_UNUSED; + + /** + * Communicate character creation to the server. + */ + void attemptCharCreate(); + + void updateHair(); + + void updateRace(); + + void updateLook(); + + CharSelectDialog *mCharSelectDialog; + + TextField *mNameField; + Label *mNameLabel; + Button *mNextHairColorButton; + Button *mPrevHairColorButton; + Label *mHairColorLabel; + Label *mHairColorNameLabel; + Button *mNextHairStyleButton; + Button *mPrevHairStyleButton; + Label *mHairStyleLabel; + Label *mHairStyleNameLabel; + Button *mNextRaceButton; + Button *mPrevRaceButton; + Label *mRaceLabel; + Label *mRaceNameLabel; + Button *mNextLookButton; + Button *mPrevLookButton; + Label *mLookLabel; + Label *mLookNameLabel; + + Button *mActionButton; + Button *mRotateButton; + + RadioButton *mMale; + RadioButton *mFemale; + RadioButton *mOther; + + std::vector mAttributeSlider; + std::vector mAttributeLabel; + std::vector mAttributeValue; + Label *mAttributesLeft; + + int mMaxPoints; + int mUsedPoints; + + Button *mCreateButton; + Button *mCancelButton; + + int mRace; + int mLook; + int mMinLook; + int mMaxLook; + + Being *mPlayer; + PlayerBox *mPlayerBox; + + int mHairStyle; + int mHairColor; + + int mSlot; + + unsigned maxHairColor; + unsigned minHairColor; + unsigned maxHairStyle; + unsigned minHairStyle; + + unsigned mAction; + unsigned mDirection; +}; + +#endif // GUI_CHARCREATEDIALOG_H diff --git a/src/gui/windows/charselectdialog.cpp b/src/gui/windows/charselectdialog.cpp new file mode 100644 index 000000000..f34f53d28 --- /dev/null +++ b/src/gui/windows/charselectdialog.cpp @@ -0,0 +1,587 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/charselectdialog.h" + +#include "client.h" +#include "configuration.h" +#include "units.h" + +#include "input/keydata.h" +#include "input/keyevent.h" + +#include "gui/windows/charcreatedialog.h" +#include "gui/windows/confirmdialog.h" +#include "gui/windows/logindialog.h" +#include "gui/windows/okdialog.h" +#include "gui/windows/textdialog.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/characterdisplay.h" +#include "gui/widgets/characterviewnormal.h" +#include "gui/widgets/characterviewsmall.h" +#include "gui/widgets/layout.h" + +#include "net/logindata.h" +#include "net/loginhandler.h" + +#include "utils/gettext.h" + +#include "debug.h" + +// Character slots per row in the dialog +static const int SLOTS_PER_ROW = 5; + +/** + * Listener for confirming character deletion. + */ +class CharDeleteConfirm final : public ConfirmDialog +{ + public: + CharDeleteConfirm(CharSelectDialog *const m, const int index) : + // TRANSLATORS: char deletion message + ConfirmDialog(_("Confirm Character Delete"), + // TRANSLATORS: char deletion message + _("Are you sure you want to delete this character?"), + SOUND_REQUEST, false, false, m), + mMaster(m), + mIndex(index) + { + } + + A_DELETE_COPY(CharDeleteConfirm) + + void action(const gcn::ActionEvent &event) + { + if (event.getId() == "yes" && mMaster) + mMaster->askPasswordForDeletion(mIndex); + + ConfirmDialog::action(event); + } + + private: + CharSelectDialog *mMaster; + int mIndex; +}; + +CharSelectDialog::CharSelectDialog(LoginData *const data): + // TRANSLATORS: char select dialog name + Window(strprintf(_("Account %s (last login time %s)"), + data->username.c_str(), data->lastLogin.c_str()), + false, nullptr, "char.xml"), + gcn::ActionListener(), + gcn::KeyListener(), + mLoginData(data), + // TRANSLATORS: char select dialog. button. + mSwitchLoginButton(new Button(this, _("Switch Login"), "switch", this)), + // TRANSLATORS: char select dialog. button. + mChangePasswordButton(new Button(this, _("Change Password"), + "change_password", this)), + mUnregisterButton(nullptr), + mChangeEmailButton(nullptr), + // TRANSLATORS: char select dialog. button. + mPlayButton(new Button(this, _("Play"), "use", this)), + // TRANSLATORS: char select dialog. button. + mInfoButton(new Button(this, _("Info"), "info", this)), + // TRANSLATORS: char select dialog. button. + mDeleteButton(new Button(this, _("Delete"), "delete", this)), + mCharacterView(nullptr), + mCharacterEntries(0), + mCharServerHandler(Net::getCharServerHandler()), + mDeleteDialog(nullptr), + mDeleteIndex(-1), + mLocked(false), + mSmallScreen(mainGraphics->getWidth() < 470 + || mainGraphics->getHeight() < 370) +{ + setCloseButton(true); + setFocusable(true); + + const int optionalActions = Net::getLoginHandler() + ->supportedOptionalActions(); + + ContainerPlacer placer; + placer = getPlacer(0, 0); + + placer(0, 0, mSwitchLoginButton); + + int n = 1; + if (optionalActions & Net::LoginHandler::Unregister) + { + // TRANSLATORS: char select dialog. button. + mUnregisterButton = new Button(this, _("Unregister"), + "unregister", this); + placer(n, 0, mUnregisterButton); + n ++; + } + + placer(n, 0, mChangePasswordButton); + n ++; + + if (optionalActions & Net::LoginHandler::ChangeEmail) + { + // TRANSLATORS: char select dialog. button. + mChangeEmailButton = new Button(this, _("Change Email"), + "change_email", this); + placer(n, 0, mChangeEmailButton); + n ++; + } + + placer(n, 0, mDeleteButton); + n ++; + placer(n, 0, mInfoButton); + n ++; + + for (int i = 0; i < static_cast(mLoginData->characterSlots); i++) + { + CharacterDisplay *const character = new CharacterDisplay(this, this); + character->setVisible(false); + mCharacterEntries.push_back(character); + } + + placer(0, 2, mPlayButton); + + if (!mSmallScreen) + { + mCharacterView = new CharacterViewNormal( + this, &mCharacterEntries, mPadding); + placer(0, 1, mCharacterView, 10); + int sz = 410 + 2 * mPadding; + if (config.getIntValue("fontSize") > 18) + sz = 500 + 2 * mPadding; + const int width = mCharacterView->getWidth() + 2 * mPadding; + if (sz < width) + sz = width; + if (sz > mainGraphics->getWidth()) + sz = mainGraphics->getWidth(); + reflowLayout(sz); + } + else + { + // TRANSLATORS: char select dialog name + setCaption(strprintf(_("Account %s"), mLoginData->username.c_str())); + mCharacterView = new CharacterViewSmall( + this, &mCharacterEntries, mPadding); + mCharacterView->setWidth(mainGraphics->getWidth() + - 2 * getPadding()); + placer(0, 1, mCharacterView, 10); + reflowLayout(); + } + addKeyListener(this); + center(); + setVisible(true); + requestFocus(); + + Net::getCharServerHandler()->setCharSelectDialog(this); + mCharacterView->show(0); + updateState(); +} + +CharSelectDialog::~CharSelectDialog() +{ +} + +void CharSelectDialog::action(const gcn::ActionEvent &event) +{ + // Check if a button of a character was pressed + const gcn::Widget *const sourceParent = event.getSource()->getParent(); + int selected = -1; + for (unsigned int i = 0, sz = static_cast( + mCharacterEntries.size()); i < sz; ++i) + { + if (mCharacterEntries[i] == sourceParent) + { + selected = i; + mCharacterView->show(i); + updateState(); + break; + } + } + if (selected == -1) + selected = mCharacterView->getSelected(); + + const std::string &eventId = event.getId(); + + if (selected >= 0) + { + if (eventId == "use") + { + use(selected); + return; + } + else if (eventId == "delete" + && mCharacterEntries[selected]->getCharacter()) + { + new CharDeleteConfirm(this, selected); + return; + } + else if (eventId == "info") + { + Net::Character *const character = mCharacterEntries[ + selected]->getCharacter(); + if (!character) + return; + + const LocalPlayer *const data = character->dummy; + if (!data) + return; + + const std::string msg = strprintf( + // TRANSLATORS: char select dialog. player info message. + _("Hp: %u/%u\nMp: %u/%u\nLevel: %u\n" + "Experience: %u\nMoney: %s"), + character->data.mAttributes[PlayerInfo::HP], + character->data.mAttributes[PlayerInfo::MAX_HP], + character->data.mAttributes[PlayerInfo::MP], + character->data.mAttributes[PlayerInfo::MAX_MP], + character->data.mAttributes[PlayerInfo::LEVEL], + character->data.mAttributes[PlayerInfo::EXP], + Units::formatCurrency( + character->data.mAttributes[PlayerInfo::MONEY]).c_str()); + new OkDialog(data->getName(), msg, DIALOG_SILENCE); + } + } + if (eventId == "switch") + { + Net::getCharServerHandler()->clear(); + close(); + } + else if (eventId == "change_password") + { + client->setState(STATE_CHANGEPASSWORD); + } + else if (eventId == "change_email") + { + client->setState(STATE_CHANGEEMAIL); + } + else if (eventId == "unregister") + { + Net::getCharServerHandler()->clear(); + client->setState(STATE_UNREGISTER); + } + else if (eventId == "try delete character") + { + if (mDeleteDialog && mDeleteIndex != -1 && mDeleteDialog->getText() + == LoginDialog::savedPassword) + { + attemptCharacterDelete(mDeleteIndex); + mDeleteDialog = nullptr; + } + else + { + // TRANSLATORS: error message + new OkDialog(_("Error"), _("Incorrect password"), DIALOG_ERROR); + } + mDeleteIndex = -1; + } +} + +void CharSelectDialog::use(const int selected) +{ + if (mCharacterEntries[selected] + && mCharacterEntries[selected]->getCharacter()) + { + attemptCharacterSelect(selected); + } + else + { + CharCreateDialog *const charCreateDialog = + new CharCreateDialog(this, selected); + mCharServerHandler->setCharCreateDialog(charCreateDialog); + } +} + +void CharSelectDialog::keyPressed(gcn::KeyEvent &keyEvent) +{ + const int actionId = static_cast(&keyEvent)->getActionId(); + switch (actionId) + { + case Input::KEY_GUI_CANCEL: + keyEvent.consume(); + action(gcn::ActionEvent(mSwitchLoginButton, + mSwitchLoginButton->getActionEventId())); + break; + + case Input::KEY_GUI_RIGHT: + { + keyEvent.consume(); + int idx = mCharacterView->getSelected(); + if (idx >= 0) + { + idx ++; + if (idx == SLOTS_PER_ROW) + break; + mCharacterView->show(idx); + updateState(); + } + break; + } + + case Input::KEY_GUI_LEFT: + { + keyEvent.consume(); + int idx = mCharacterView->getSelected(); + if (idx >= 0) + { + if (!idx || idx == SLOTS_PER_ROW) + break; + idx --; + mCharacterView->show(idx); + updateState(); + } + break; + } + + case Input::KEY_GUI_UP: + { + keyEvent.consume(); + int idx = mCharacterView->getSelected(); + if (idx >= 0) + { + if (idx < SLOTS_PER_ROW) + break; + idx -= SLOTS_PER_ROW; + mCharacterView->show(idx); + updateState(); + } + break; + } + + case Input::KEY_GUI_DOWN: + { + keyEvent.consume(); + int idx = mCharacterView->getSelected(); + if (idx >= 0) + { + if (idx >= SLOTS_PER_ROW) + break; + idx += SLOTS_PER_ROW; + mCharacterView->show(idx); + updateState(); + } + break; + } + + case Input::KEY_GUI_DELETE: + { + keyEvent.consume(); + const int idx = mCharacterView->getSelected(); + if (idx >= 0 && mCharacterEntries[idx] + && mCharacterEntries[idx]->getCharacter()) + { + new CharDeleteConfirm(this, idx); + } + break; + } + + case Input::KEY_GUI_SELECT: + { + keyEvent.consume(); + use(mCharacterView->getSelected()); + break; + } + default: + break; + } +} + +/** + * Communicate character deletion to the server. + */ +void CharSelectDialog::attemptCharacterDelete(const int index) +{ + if (mLocked) + return; + + if (mCharacterEntries[index]) + { + mCharServerHandler->deleteCharacter( + mCharacterEntries[index]->getCharacter()); + } + lock(); +} + +void CharSelectDialog::askPasswordForDeletion(const int index) +{ + mDeleteIndex = index; + mDeleteDialog = new TextDialog( + // TRANSLATORS: char deletion question. + _("Enter password for deleting character"), _("Enter password:"), + this, true); + mDeleteDialog->setActionEventId("try delete character"); + mDeleteDialog->addActionListener(this); +} + +/** + * Communicate character selection to the server. + */ +void CharSelectDialog::attemptCharacterSelect(const int index) +{ + if (mLocked || !mCharacterEntries[index]) + return; + + setVisible(false); + if (mCharServerHandler) + { + mCharServerHandler->chooseCharacter( + mCharacterEntries[index]->getCharacter()); + } + lock(); +} + +void CharSelectDialog::setCharacters(const Net::Characters &characters) +{ + // Reset previous characters + FOR_EACH (std::vector::const_iterator, + iter, mCharacterEntries) + { + if (*iter) + (*iter)->setCharacter(nullptr); + } + + FOR_EACH (Net::Characters::const_iterator, i, characters) + { + if (!*i) + continue; + + Net::Character *const character = *i; + + // Slots Number start at 1 for Manaserv, so we offset them by one. +#ifdef MANASERV_SUPPORT + int characterSlot = character->slot; + if (Net::getNetworkType() == ServerInfo::MANASERV && characterSlot > 0) + --characterSlot; +#else + const int characterSlot = character->slot; +#endif + + if (characterSlot >= static_cast(mCharacterEntries.size())) + { + logger->log("Warning: slot out of range: %d", character->slot); + continue; + } + + if (mCharacterEntries[characterSlot]) + mCharacterEntries[characterSlot]->setCharacter(character); + } + + updateState(); +} + +void CharSelectDialog::lock() +{ + if (!mLocked) + setLocked(true); +} + +void CharSelectDialog::unlock() +{ + setLocked(false); +} + +void CharSelectDialog::setLocked(const bool locked) +{ + mLocked = locked; + + if (mSwitchLoginButton) + mSwitchLoginButton->setEnabled(!locked); + if (mChangePasswordButton) + mChangePasswordButton->setEnabled(!locked); + if (mUnregisterButton) + mUnregisterButton->setEnabled(!locked); + if (mChangeEmailButton) + mChangeEmailButton->setEnabled(!locked); + if (mPlayButton) + mPlayButton->setEnabled(!locked); + if (mDeleteButton) + mDeleteButton->setEnabled(!locked); + + for (size_t i = 0, sz = mCharacterEntries.size(); i < sz; ++i) + { + if (mCharacterEntries[i]) + mCharacterEntries[i]->setActive(!mLocked); + } +} + +bool CharSelectDialog::selectByName(const std::string &name, + const SelectAction selAction) +{ + if (mLocked) + return false; + + for (size_t i = 0, sz = mCharacterEntries.size(); i < sz; ++i) + { + if (mCharacterEntries[i]) + { + const Net::Character *const character + = mCharacterEntries[i]->getCharacter(); + if (character) + { + if (character->dummy && character->dummy->getName() == name) + { + mCharacterView->show(static_cast(i)); + updateState(); + if (selAction == Choose) + attemptCharacterSelect(static_cast(i)); + return true; + } + } + } + } + + return false; +} + +void CharSelectDialog::close() +{ + client->setState(STATE_SWITCH_LOGIN); + Window::close(); +} + +void CharSelectDialog::widgetResized(const gcn::Event &event) +{ + Window::widgetResized(event); + if (mCharacterView) + mCharacterView->resize(); +} + +void CharSelectDialog::updateState() +{ + const int idx = mCharacterView->getSelected(); + if (idx == -1) + { + mPlayButton->setEnabled(false); + return; + } + mPlayButton->setEnabled(true); + + if (mCharacterEntries[idx] && mCharacterEntries[idx]->getCharacter()) + { + // TRANSLATORS: char select dialog. button. + mPlayButton->setCaption(_("Play")); + } + else + { + // TRANSLATORS: char select dialog. button. + mPlayButton->setCaption(_("Create")); + } +} diff --git a/src/gui/windows/charselectdialog.h b/src/gui/windows/charselectdialog.h new file mode 100644 index 000000000..9556ba633 --- /dev/null +++ b/src/gui/windows/charselectdialog.h @@ -0,0 +1,126 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_CHARSELECTDIALOG_H +#define GUI_CHARSELECTDIALOG_H + +#include "main.h" + +#include "gui/widgets/window.h" + +#include "net/charserverhandler.h" + +#include +#include + +class Button; +class CharacterDisplay; +class CharacterViewBase; +class Label; +class LoginData; +class TextDialog; + +/** + * Character selection dialog. + * + * \ingroup Interface + */ +class CharSelectDialog final : public Window, + public gcn::ActionListener, + public gcn::KeyListener +{ + public: + friend class CharDeleteConfirm; + friend class Net::CharServerHandler; + + /** + * Constructor. + */ + explicit CharSelectDialog(LoginData *const data); + + A_DELETE_COPY(CharSelectDialog) + + ~CharSelectDialog(); + + void action(const gcn::ActionEvent &event) override; + + void keyPressed(gcn::KeyEvent &keyEvent) override; + + enum SelectAction + { + Focus = 0, + Choose + }; + + /** + * Attempt to select the character with the given name. Returns whether + * a character with the given name was found. + * + * \param action determines what to do when a character with the given + * name was found (just focus or also try to choose this + * character). + */ + bool selectByName(const std::string &name, + const SelectAction action = Focus); + + void askPasswordForDeletion(const int index); + + void close() override; + + void widgetResized(const gcn::Event &event) override; + + void updateState(); + + private: + void attemptCharacterDelete(const int index); + + void attemptCharacterSelect(const int index); + + void setCharacters(const Net::Characters &characters); + + void use(const int selected); + + void lock(); + void unlock(); + void setLocked(const bool locked); + + LoginData *mLoginData; + + Button *mSwitchLoginButton; + Button *mChangePasswordButton; + Button *mUnregisterButton; + Button *mChangeEmailButton; + Button *mPlayButton; + Button *mInfoButton; + Button *mDeleteButton; + CharacterViewBase *mCharacterView; + + std::vector mCharacterEntries; + + Net::CharServerHandler *mCharServerHandler; + TextDialog *mDeleteDialog; + int mDeleteIndex; + bool mLocked; + bool mSmallScreen; +}; + +#endif // GUI_CHARSELECTDIALOG_H diff --git a/src/gui/windows/chatwindow.cpp b/src/gui/windows/chatwindow.cpp new file mode 100644 index 000000000..61f42a824 --- /dev/null +++ b/src/gui/windows/chatwindow.cpp @@ -0,0 +1,1795 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/chatwindow.h" + +#include "actorspritemanager.h" +#include "client.h" +#include "commandhandler.h" +#include "configuration.h" +#include "game.h" +#include "guild.h" +#include "party.h" +#include "spellshortcut.h" + +#include "being/localplayer.h" +#include "being/playerinfo.h" +#include "being/playerrelations.h" + +#include "input/inputmanager.h" +#include "input/keyevent.h" + +#include "gui/gui.h" +#include "gui/sdlfont.h" +#include "gui/sdlinput.h" +#include "gui/viewport.h" + +#include "gui/windows/emotewindow.h" +#include "gui/windows/setup.h" +#include "gui/windows/whoisonline.h" + +#include "gui/widgets/battletab.h" +#include "gui/widgets/dropdown.h" +#include "gui/widgets/itemlinkhandler.h" +#include "gui/widgets/langtab.h" +#include "gui/widgets/scrollarea.h" +#include "gui/widgets/textfield.h" +#include "gui/widgets/tradetab.h" +#include "gui/widgets/whispertab.h" + +#include "net/chathandler.h" +#include "net/playerhandler.h" +#include "net/net.h" + +#include "utils/copynpaste.h" +#include "utils/gettext.h" + +#include "resources/resourcemanager.h" + +#include + +#include + +#include + +#include "debug.h" + +/** + * The chat input hides when it loses focus. It is also invisible by default. + */ +class ChatInput final : public TextField +{ + public: + explicit ChatInput(ChatWindow *const window): + TextField(window, "", false), + mWindow(window), + mFocusGaining(false) + { + setVisible(false); + addFocusListener(this); + } + + A_DELETE_COPY(ChatInput) + + /** + * Called if the chat input loses focus. It will set itself to + * invisible as result. + */ + void focusLost(const gcn::Event &event) + { + TextField::focusLost(event); + if (mFocusGaining || !config.getBoolValue("protectChatFocus")) + { + processVisible(false); + if (chatWindow) + chatWindow->updateVisibility(); + mFocusGaining = false; + return; + } + mFocusGaining = true; + requestFocus(); + mFocusGaining = false; + } + + void processVisible(const bool n) + { + if (!mWindow || isVisible() == n) + return; + + if (!n) + mFocusGaining = true; + setVisible(n); + if (config.getBoolValue("hideChatInput")) + mWindow->adjustTabSize(); + if (emoteWindow) + emoteWindow->hide(); + } + + void unprotectFocus() + { mFocusGaining = true; } + + void setVisible(bool visible) + { + TextField::setVisible(visible); + } + + private: + ChatWindow *mWindow; + bool mFocusGaining; +}; + +const char *COLOR_NAME[14] = +{ + // TRANSLATORS: chat color + N_("default"), + // TRANSLATORS: chat color + N_("black"), + // TRANSLATORS: chat color + N_("red"), + // TRANSLATORS: chat color + N_("green"), + // TRANSLATORS: chat color + N_("blue"), + // TRANSLATORS: chat color + N_("gold"), + // TRANSLATORS: chat color + N_("yellow"), + // TRANSLATORS: chat color + N_("pink"), + // TRANSLATORS: chat color + N_("purple"), + // TRANSLATORS: chat color + N_("grey"), + // TRANSLATORS: chat color + N_("brown"), + // TRANSLATORS: chat color + N_("rainbow 1"), + // TRANSLATORS: chat color + N_("rainbow 2"), + // TRANSLATORS: chat color + N_("rainbow 3"), +}; + + +class ColorListModel final : public gcn::ListModel +{ +public: + ~ColorListModel() + { } + + int getNumberOfElements() + { + return 14; + } + + std::string getElementAt(int i) + { + if (i >= getNumberOfElements() || i < 0) + return "???"; + return gettext(COLOR_NAME[i]); + } +}; + +static const char *const ACTION_COLOR_PICKER = "color picker"; + +ChatWindow::ChatWindow(): + // TRANSLATORS: chat window name + Window(_("Chat"), false, nullptr, "chat.xml"), + gcn::ActionListener(), + gcn::KeyListener(), + mItemLinkHandler(new ItemLinkHandler), + mChatTabs(new TabbedArea(this)), + mChatInput(new ChatInput(this)), + mRainbowColor(0), + mWhispers(), + mHistory(), + mCurHist(), + mCommands(), + mCustomWords(), + mReturnToggles(config.getBoolValue("ReturnToggles")), + mTradeFilter(), + mColorListModel(new ColorListModel), + mColorPicker(new DropDown(this, mColorListModel)), + mChatColor(config.getIntValue("chatColor")), + mChatHistoryIndex(0), + mAwayLog(), + mHighlights(), + mGlobalsFilter(), + mGMLoaded(false), + mHaveMouse(false), + mAutoHide(config.getBoolValue("autohideChat")), + mShowBattleEvents(config.getBoolValue("showBattleEvents")), + mShowAllLang(serverConfig.getValue("showAllLang", 0)), + mTmpVisible(false) +{ + listen(CHANNEL_ATTRIBUTES); + + setWindowName("Chat"); + + if (setupWindow) + setupWindow->registerWindowForReset(this); + + setShowTitle(false); + setResizable(true); + setDefaultVisible(true); + setSaveVisible(true); + setStickyButtonLock(true); + + int w = 600; +#ifdef ANDROID + if (mainGraphics->getWidth() < 710) + w = mainGraphics->getWidth() - 110; + if (w < 100) + w = 100; + if (mainGraphics->getHeight() < 480) + setDefaultSize(w, 90, ImageRect::UPPER_LEFT, -110, -35); + else + setDefaultSize(w, 123, ImageRect::UPPER_LEFT, -110, -35); +#else + if (mainGraphics->getWidth() < 600) + w = mainGraphics->getWidth() - 10; + if (w < 100) + w = 100; + setDefaultSize(w, 123, ImageRect::LOWER_LEFT); +#endif + setMinWidth(150); + setMinHeight(90); + + setTitleBarHeight(getPadding() + getTitlePadding()); + + if (emoteWindow) + emoteWindow->addListeners(this); + + mChatTabs->enableScrollButtons(true); + mChatTabs->setFollowDownScroll(true); + mChatTabs->setResizeHeight(false); + + mChatInput->setActionEventId("chatinput"); + mChatInput->addActionListener(this); + + mColorPicker->setActionEventId(ACTION_COLOR_PICKER); + mColorPicker->addActionListener(this); + mColorPicker->setSelected(mChatColor); + + add(mChatTabs); + add(mChatInput); + add(mColorPicker); + + loadWindowState(); + + mColorPicker->setPosition(this->getWidth() - mColorPicker->getWidth() + - 2 * mPadding - 8 - 16, mPadding); + + // Add key listener to chat input to be able to respond to up/down + mChatInput->addKeyListener(this); + mCurHist = mHistory.end(); + mColorPicker->setVisible(config.getBoolValue("showChatColorsList")); + + fillCommands(); + if (player_node && player_node->isGM()) + loadGMCommands(); + initTradeFilter(); + loadCustomList(); + parseHighlights(); + parseGlobalsFilter(); + + config.addListener("autohideChat", this); + config.addListener("showBattleEvents", this); + config.addListener("globalsFilter", this); + + enableVisibleSound(true); +} + +ChatWindow::~ChatWindow() +{ + config.removeListeners(this); + saveState(); + config.setValue("ReturnToggles", mReturnToggles); + removeAllWhispers(); + delete mItemLinkHandler; + mItemLinkHandler = nullptr; + delete mColorPicker; + mColorPicker = nullptr; + delete mColorListModel; + mColorListModel = nullptr; +} + +void ChatWindow::loadCommandsFile(const std::string &name) +{ + StringVect list; + ResourceManager::loadTextFile(name, list); + StringVectCIter it = list.begin(); + const StringVectCIter it_end = list.end(); + + while (it != it_end) + { + const std::string str = *it; + if (!str.empty()) + mCommands.push_back(str); + ++ it; + } +} + +void ChatWindow::fillCommands() +{ + loadCommandsFile("chatcommands.txt"); + CommandHandler::addChatCommands(mCommands); +} + +void ChatWindow::loadGMCommands() +{ + if (mGMLoaded) + return; + + loadCommandsFile("gmcommands.txt"); + mGMLoaded = true; +} + +void ChatWindow::adjustTabSize() +{ + const gcn::Rectangle area = getChildrenArea(); + + const int aw = area.width; + const int ah = area.height; + const int frame = mChatInput->getFrameSize(); + const int inputHeight = mChatInput->getHeight(); + const int frame2 = 2 * frame; + const int awFrame2 = aw - frame2; + mChatInput->setPosition(frame, ah - inputHeight - frame); + mChatInput->setWidth(awFrame2); + mChatTabs->setWidth(awFrame2); + const int height = ah - frame2 - (inputHeight + frame2); + if (mChatInput->isVisible() || !config.getBoolValue("hideChatInput")) + mChatTabs->setHeight(height); + else + mChatTabs->setHeight(height + inputHeight); + + const ChatTab *const tab = getFocused(); + if (tab) + { + gcn::Widget *const content = tab->mScrollArea; + if (content) + { + const int contentFrame2 = 2 * content->getFrameSize(); + content->setSize(mChatTabs->getWidth() - contentFrame2, + mChatTabs->getContainerHeight() - contentFrame2); + content->logic(); + } + } + + mColorPicker->setPosition(this->getWidth() - mColorPicker->getWidth() + - 2 * mPadding - 8 - 16, mPadding); + + mChatTabs->adjustSize(); +} + +void ChatWindow::widgetResized(const gcn::Event &event) +{ + Window::widgetResized(event); + + adjustTabSize(); +} + +ChatTab *ChatWindow::getFocused() const +{ + return static_cast(mChatTabs->getSelectedTab()); +} + +void ChatWindow::clearTab(ChatTab *const tab) const +{ + if (tab) + tab->clearText(); +} + +void ChatWindow::clearTab() const +{ + clearTab(getFocused()); +} + +void ChatWindow::prevTab() +{ + if (!mChatTabs) + return; + + int tab = mChatTabs->getSelectedTabIndex(); + + if (tab <= 0) + tab = mChatTabs->getNumberOfTabs(); + tab--; + + mChatTabs->setSelectedTabByPos(tab); +} + +void ChatWindow::nextTab() +{ + if (!mChatTabs) + return; + + int tab = mChatTabs->getSelectedTabIndex(); + + tab++; + if (tab == mChatTabs->getNumberOfTabs()) + tab = 0; + + mChatTabs->setSelectedTabByPos(tab); +} + +void ChatWindow::closeTab() const +{ + if (!mChatTabs) + return; + + Tab *const tab = mChatTabs->getTabByIndex( + mChatTabs->getSelectedTabIndex()); + if (!tab) + return; + WhisperTab *const whisper = dynamic_cast(tab); + if (!whisper) + return; + + whisper->handleCommand("close", ""); +} + +void ChatWindow::defaultTab() +{ + if (mChatTabs) + mChatTabs->setSelectedTabByPos(static_cast(0)); +} + +void ChatWindow::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "chatinput") + { + std::string message = mChatInput->getText(); + + if (!message.empty()) + { + // If message different from previous, put it in the history + if (mHistory.empty() || message != mHistory.back()) + mHistory.push_back(message); + + // Reset history iterator + mCurHist = mHistory.end(); + + // Send the message to the server + chatInput(addColors(message)); + + // Clear the text from the chat input + mChatInput->setText(""); + } + + if (message.empty() || !mReturnToggles) + { + // Remove focus and hide input + mChatInput->unprotectFocus(); + if (mFocusHandler) + mFocusHandler->focusNone(); + + // If the chatWindow is shown up because you want to send a message + // It should hide now + if (mTmpVisible) + setVisible(false); + } + } + else if (eventId == "emote") + { + if (emoteWindow) + { + const std::string str = emoteWindow->getSelectedEmote(); + if (!str.empty()) + { + addInputText(str, false); + emoteWindow->clearEmote(); + } + } + } + else if (eventId == "color") + { + if (emoteWindow) + { + const std::string str = emoteWindow->getSelectedColor(); + if (!str.empty()) + { + addInputText(str, false); + emoteWindow->clearColor(); + } + } + } + else if (eventId == "font") + { + if (emoteWindow) + { + const std::string str = emoteWindow->getSelectedFont(); + if (!str.empty()) + { + addInputText(str, false); + emoteWindow->clearFont(); + } + } + } + else if (eventId == ACTION_COLOR_PICKER) + { + if (mColorPicker) + { + mChatColor = mColorPicker->getSelected(); + config.setValue("chatColor", mChatColor); + } + } + + if (mColorPicker && mColorPicker->isVisible() + != config.getBoolValue("showChatColorsList")) + { + mColorPicker->setVisible(config.getBoolValue( + "showChatColorsList")); + } +} + +bool ChatWindow::requestChatFocus() +{ + // Make sure chatWindow is visible + if (!isWindowVisible()) + { + setVisible(true); + + /* + * This is used to hide chatWindow after sending the message. There is + * a trick here, because setVisible will set mTmpVisible to false, you + * have to put this sentence *after* setVisible, not before it + */ + mTmpVisible = true; + } + + // Don't do anything else if the input is already visible and has focus + if (mChatInput->isVisible() && mChatInput->isFocused()) + return false; + + // Give focus to the chat input + mChatInput->processVisible(true); + unHideWindow(); + mChatInput->requestFocus(); + return true; +} + +bool ChatWindow::isInputFocused() const +{ + return mChatInput->isFocused(); +} + +void ChatWindow::removeTab(ChatTab *const tab) +{ + mChatTabs->removeTab(tab); +} + +void ChatWindow::addTab(ChatTab *const tab) +{ + if (!tab) + return; + + mChatTabs->addTab(tab, tab->mScrollArea); + logic(); +} + +void ChatWindow::removeWhisper(const std::string &nick) +{ + std::string tempNick = nick; + toLower(tempNick); + mWhispers.erase(tempNick); +} + +void ChatWindow::removeAllWhispers() +{ + std::list tabs; + + FOR_EACH (TabMap::iterator, iter, mWhispers) + tabs.push_back(iter->second); + + for (std::list::iterator it = tabs.begin(); + it != tabs.end(); ++it) + { + delete *it; + } + + mWhispers.clear(); +} + +void ChatWindow::ignoreAllWhispers() +{ + for (TabMap::iterator iter = mWhispers.begin(); + iter != mWhispers.end(); + ++ iter) + { + const WhisperTab *const tab = dynamic_cast( + iter->second); + if (tab && player_relations.getRelation(tab->getNick()) + != PlayerRelation::IGNORED) + { + player_relations.setRelation(tab->getNick(), + PlayerRelation::IGNORED); + } + + delete (iter->second); + iter->second = nullptr; + } +} + +void ChatWindow::chatInput(const std::string &message) const +{ + ChatTab *tab = nullptr; + std::string msg = message; + trim(msg); + + if (config.getBoolValue("allowCommandsInChatTabs") + && msg.length() > 1 + && ((msg.at(0) == '#' && msg.at(1) != '#') || msg.at(0) == '@') + && localChatTab) + { + tab = localChatTab; + } + else + { + tab = getFocused(); + } + if (tab) + tab->chatInput(msg); + Game::instance()->setValidSpeed(); +} + +void ChatWindow::localChatInput(const std::string &msg) const +{ + if (localChatTab) + localChatTab->chatInput(msg); + else + chatInput(msg); +} + +void ChatWindow::doPresent() const +{ + if (!actorSpriteManager) + return; + + const ActorSprites &actors = actorSpriteManager->getAll(); + std::string response; + int playercount = 0; + + FOR_EACH (ActorSpritesConstIterator, it, actors) + { + if ((*it)->getType() == ActorSprite::PLAYER) + { + if (!response.empty()) + response.append(", "); + response.append(static_cast(*it)->getName()); + playercount ++; + } + } + + const std::string log = strprintf( + // TRANSLATORS: chat message + _("Present: %s; %d players are present."), + response.c_str(), playercount); + + if (getFocused()) + getFocused()->chatLog(log, BY_SERVER); +} + +void ChatWindow::scroll(const int amount) const +{ + if (!isWindowVisible()) + return; + + ChatTab *const tab = getFocused(); + if (tab) + tab->scroll(amount); +} + +void ChatWindow::mousePressed(gcn::MouseEvent &event) +{ + if (event.isConsumed()) + return; + + if (event.getButton() == gcn::MouseEvent::RIGHT) + { + if (viewport) + { + Tab *const tab = mChatTabs->getSelectedTab(); + if (tab) + { + if (inputManager.isActionActive(static_cast( + Input::KEY_CHAT_MOD))) + { + ChatTab *const wTab = dynamic_cast(tab); + if (wTab) + wTab->handleCommand("close", ""); + } + else + { + ChatTab *const cTab = dynamic_cast(tab); + if (cTab) + viewport->showChatPopup(cTab); + } + } + } + } + + Window::mousePressed(event); + + if (event.isConsumed()) + return; + + if (event.getButton() == gcn::MouseEvent::LEFT) + { + const ChatTab *const tab = getFocused(); + if (tab) + mMoved = !isResizeAllowed(event); + } + + mDragOffsetX = event.getX(); + mDragOffsetY = event.getY(); +} + +void ChatWindow::mouseDragged(gcn::MouseEvent &event) +{ + Window::mouseDragged(event); + + if (event.isConsumed()) + return; + + if (canMove() && isMovable() && mMoved) + { + int newX = std::max(0, getX() + event.getX() - mDragOffsetX); + int newY = std::max(0, getY() + event.getY() - mDragOffsetY); + newX = std::min(mainGraphics->mWidth - getWidth(), newX); + newY = std::min(mainGraphics->mHeight - getHeight(), newY); + setPosition(newX, newY); + } +} + +#define caseKey(key, str) case key:\ + temp = str; \ + break + +void ChatWindow::keyPressed(gcn::KeyEvent &event) +{ + const int key = event.getKey().getValue(); + const int actionId = static_cast(&event)->getActionId(); + if (actionId == static_cast(Input::KEY_GUI_DOWN)) + { + if (mCurHist != mHistory.end()) + { + // Move forward through the history + const HistoryIterator prevHist = mCurHist++; + + if (mCurHist != mHistory.end()) + { + mChatInput->setText(*mCurHist); + mChatInput->setCaretPosition(static_cast( + mChatInput->getText().length())); + } + else + { + mChatInput->setText(""); + mCurHist = prevHist; + } + } + else if (!mChatInput->getText().empty()) + { + mChatInput->setText(""); + } + } + else if (actionId == static_cast(Input::KEY_GUI_UP) && + mCurHist != mHistory.begin() && !mHistory.empty()) + { + // Move backward through the history + --mCurHist; + mChatInput->setText(*mCurHist); + mChatInput->setCaretPosition(static_cast( + mChatInput->getText().length())); + } + else if (actionId == static_cast(Input::KEY_GUI_INSERT) && + mChatInput->getText() != "") + { + // Add the current message to the history and clear the text + if (mHistory.empty() || mChatInput->getText() != mHistory.back()) + mHistory.push_back(mChatInput->getText()); + mCurHist = mHistory.end(); + mChatInput->setText(""); + } + else if (actionId == static_cast(Input::KEY_GUI_TAB) && + !mChatInput->getText().empty()) + { + autoComplete(); + return; + } + else if (actionId == static_cast(Input::KEY_GUI_CANCEL) && + mChatInput->isVisible()) + { + mChatInput->processVisible(false); + } + else if (actionId == static_cast(Input::KEY_CHAT_PREV_HISTORY) && + mChatInput->isVisible()) + { + const ChatTab *const tab = getFocused(); + if (tab && tab->hasRows()) + { + if (!mChatHistoryIndex) + { + mChatHistoryIndex = static_cast( + tab->getRows().size()); + + mChatInput->setText(""); + mChatInput->setCaretPosition(0); + return; + } + else + { + mChatHistoryIndex --; + } + + unsigned int f = 0; + const std::list &rows = tab->getRows(); + for (std::list::const_iterator it = rows.begin(), + it_end = rows.end(); it != it_end; ++ it, f ++) + { + if (f == mChatHistoryIndex) + mChatInput->setText(*it); + } + mChatInput->setCaretPosition(static_cast( + mChatInput->getText().length())); + } + } + else if (actionId == static_cast(Input::KEY_CHAT_NEXT_HISTORY) && + mChatInput->isVisible()) + { + const ChatTab *const tab = getFocused(); + if (tab && tab->hasRows()) + { + const std::list &rows = tab->getRows(); + const size_t &tabSize = rows.size(); + if (mChatHistoryIndex + 1 < tabSize) + { + mChatHistoryIndex ++; + } + else if (mChatHistoryIndex < tabSize) + { + mChatHistoryIndex ++; + mChatInput->setText(""); + mChatInput->setCaretPosition(0); + return; + } + else + { + mChatHistoryIndex = 0; + } + + unsigned int f = 0; + for (std::list::const_iterator + it = rows.begin(), it_end = rows.end(); + it != it_end; ++it, f++) + { + if (f == mChatHistoryIndex) + mChatInput->setText(*it); + } + mChatInput->setCaretPosition(static_cast( + mChatInput->getText().length())); + } + } + + std::string temp; + switch (key) + { + case Key::F1: + if (emoteWindow) + emoteWindow->show(); + break; + caseKey(Key::F2, "\u2318"); + caseKey(Key::F3, "\u263A"); + caseKey(Key::F4, "\u2665"); + caseKey(Key::F5, "\u266A"); + caseKey(Key::F6, "\u266B"); + caseKey(Key::F7, "\u26A0"); + caseKey(Key::F8, "\u2622"); + caseKey(Key::F9, "\u262E"); + caseKey(Key::F10, "\u2605"); + caseKey(Key::F11, "\u2618"); + caseKey(Key::F12, "\u2592"); + default: + break; + } + + if (!temp.empty()) + addInputText(temp, false); +} + +void ChatWindow::processEvent(const Channels channel, + const DepricatedEvent &event) +{ + if (channel == CHANNEL_ATTRIBUTES) + { + if (!mShowBattleEvents) + return; + + if (event.getName() == EVENT_UPDATEATTRIBUTE) + { + switch (event.getInt("id")) + { + case PlayerInfo::EXP: + { + if (event.getInt("oldValue") > event.getInt("newValue")) + break; + + const int change = event.getInt("newValue") + - event.getInt("oldValue"); + + if (change != 0) + { + battleChatLog(std::string("+").append(toString( + change)).append(" xp")); + } + break; + } + case PlayerInfo::LEVEL: + battleChatLog(std::string("Level: ").append(toString( + event.getInt("newValue")))); + break; + default: + break; + }; + } + else if (event.getName() == EVENT_UPDATESTAT) + { + if (!config.getBoolValue("showJobExp")) + return; + + const int id = event.getInt("id"); + if (id == Net::getPlayerHandler()->getJobLocation()) + { + const std::pair exp + = PlayerInfo::getStatExperience(id); + if (event.getInt("oldValue1") > exp.first + || !event.getInt("oldValue2")) + { + return; + } + + const int change = exp.first - event.getInt("oldValue1"); + if (change != 0) + { + battleChatLog(std::string("+").append( + toString(change)).append(" job")); + } + } + } + } +} + +void ChatWindow::addInputText(const std::string &text, const bool space) +{ + const int caretPos = mChatInput->getCaretPosition(); + const std::string inputText = mChatInput->getText(); + + std::ostringstream ss; + ss << inputText.substr(0, caretPos) << text; + if (space) + ss << " "; + + ss << inputText.substr(caretPos); + mChatInput->setText(ss.str()); + mChatInput->setCaretPosition(caretPos + static_cast( + text.length()) + static_cast(space)); + requestChatFocus(); +} + +void ChatWindow::addItemText(const std::string &item) +{ + std::ostringstream text; + text << "[" << item << "]"; + addInputText(text.str()); +} + +void ChatWindow::setVisible(bool visible) +{ + Window::setVisible(visible); + + /* + * For whatever reason, if setVisible is called, the mTmpVisible effect + * should be disabled. + */ + mTmpVisible = false; +} + +void ChatWindow::addWhisper(const std::string &nick, + const std::string &mes, const Own own) +{ + if (mes.empty() || !player_node) + return; + + std::string playerName = player_node->getName(); + std::string tempNick = nick; + + toLower(playerName); + toLower(tempNick); + + if (tempNick.compare(playerName) == 0) + return; + + WhisperTab *tab = nullptr; + const TabMap::const_iterator i = mWhispers.find(tempNick); + + if (i != mWhispers.end()) + { + tab = i->second; + } + else if (config.getBoolValue("whispertab")) + { + tab = addWhisperTab(nick); + if (tab) + saveState(); + } + + if (tab) + { + if (own == BY_PLAYER) + { + tab->chatInput(mes); + } + else if (own == BY_SERVER) + { + tab->chatLog(mes); + } + else + { + if (tab->getRemoveNames()) + { + std::string msg = mes; + const size_t idx = mes.find(":"); + if (idx != std::string::npos && idx > 0) + { + std::string nick2 = msg.substr(0, idx); + msg = msg.substr(idx + 1); + nick2 = removeColors(nick2); + nick2 = trim(nick2); + if (config.getBoolValue("removeColors")) + msg = removeColors(msg); + msg = trim(msg); + tab->chatLog(nick2, msg); + } + else + { + if (config.getBoolValue("removeColors")) + msg = removeColors(msg); + tab->chatLog(msg, BY_SERVER); + } + } + else + { + tab->chatLog(nick, mes); + } + player_node->afkRespond(tab, nick); + } + } + else if (localChatTab) + { + if (own == BY_PLAYER) + { + Net::getChatHandler()->privateMessage(nick, mes); + + // TRANSLATORS: chat message + localChatTab->chatLog(strprintf(_("Whispering to %s: %s"), + nick.c_str(), mes.c_str()), BY_PLAYER); + } + else + { + localChatTab->chatLog(std::string(nick).append( + " : ").append(mes), ACT_WHISPER, false); + if (player_node) + player_node->afkRespond(nullptr, nick); + } + } +} + +WhisperTab *ChatWindow::addWhisperTab(const std::string &nick, + const bool switchTo) +{ + if (!player_node) + return nullptr; + + std::string playerName = player_node->getName(); + std::string tempNick = nick; + + toLower(playerName); + toLower(tempNick); + + const TabMap::const_iterator i = mWhispers.find(tempNick); + WhisperTab *ret; + + if (tempNick.compare(playerName) == 0) + return nullptr; + + if (i != mWhispers.end()) + { + ret = i->second; + } + else + { + ret = new WhisperTab(this, nick); + if (gui && !player_relations.isGoodName(nick)) + ret->setLabelFont(gui->getSecureFont()); + mWhispers[tempNick] = ret; + if (config.getBoolValue("showChatHistory")) + ret->loadFromLogFile(nick); + } + + if (switchTo) + mChatTabs->setSelectedTab(ret); + + return ret; +} + +WhisperTab *ChatWindow::getWhisperTab(const std::string &nick) const +{ + if (!player_node) + return nullptr; + + std::string playerName = player_node->getName(); + std::string tempNick = nick; + + toLower(playerName); + toLower(tempNick); + + const TabMap::const_iterator i = mWhispers.find(tempNick); + WhisperTab *ret = nullptr; + + if (tempNick.compare(playerName) == 0) + return nullptr; + + if (i != mWhispers.end()) + ret = i->second; + + return ret; +} + +std::string ChatWindow::addColors(std::string &msg) +{ + // default color or chat command + if (mChatColor == 0 || msg.length() == 0 || msg.at(0) == '#' + || msg.at(0) == '/' || msg.at(0) == '@' || msg.at(0) == '!') + { + return msg; + } + + std::string newMsg(""); + const int cMap[] = {1, 4, 5, 2, 3, 6, 7, 9, 0, 8}; + + // rainbow + switch (mChatColor) + { + case 11: + msg = removeColors(msg); + for (unsigned int f = 0; f < msg.length(); f ++) + { + newMsg += "##" + toString(mRainbowColor++) + msg.at(f); + if (mRainbowColor > 9) + mRainbowColor = 0; + } + return newMsg; + case 12: + msg = removeColors(msg); + for (unsigned int f = 0; f < msg.length(); f ++) + { + newMsg += "##" + toString(cMap[mRainbowColor++]) + msg.at(f); + if (mRainbowColor > 9) + mRainbowColor = 0; + } + return newMsg; + case 13: + msg = removeColors(msg); + for (unsigned int f = 0; f < msg.length(); f ++) + { + newMsg += "##" + toString(cMap[9-mRainbowColor++]) + msg.at(f); + if (mRainbowColor > 9) + mRainbowColor = 0; + } + return newMsg; + default: + break; + } + + // simple colors + return std::string("##").append(toString(mChatColor - 1)).append(msg); +} + +void ChatWindow::autoComplete() +{ + const int caretPos = mChatInput->getCaretPosition(); + int startName = 0; + const std::string inputText = mChatInput->getText(); + bool needSecure(false); + std::string name = inputText.substr(0, caretPos); + + for (int f = caretPos - 1; f > -1; f --) + { + if (isWordSeparator(inputText[f])) + { + startName = f + 1; + name = inputText.substr(f + 1, caretPos - f); + break; + } + } + + if (caretPos - 1 + 1 == startName) + return; + + const ChatTab *const cTab = static_cast( + mChatTabs->getSelectedTab()); + StringVect nameList; + + if (cTab) + cTab->getAutoCompleteList(nameList); + std::string newName = autoComplete(nameList, name); + if (!newName.empty()) + needSecure = true; + + if (newName.empty() && actorSpriteManager) + { + actorSpriteManager->getPlayerNames(nameList, true); + newName = autoComplete(nameList, name); + if (!newName.empty()) + needSecure = true; + } + if (newName.empty()) + newName = autoCompleteHistory(name); + if (newName.empty() && spellManager) + newName = spellManager->autoComplete(name); + if (newName.empty()) + newName = autoComplete(name, &mCommands); + if (newName.empty() && actorSpriteManager) + { + actorSpriteManager->getMobNames(nameList); + newName = autoComplete(nameList, name); + } + if (newName.empty()) + newName = autoComplete(name, &mCustomWords); + if (newName.empty()) + { + whoIsOnline->getPlayerNames(nameList); + newName = autoComplete(nameList, name); + } + + if (!newName.empty()) + { + if (!startName && needSecure && (newName[0] == '/' + || newName[0] == '@' || newName[0] == '#')) + { + newName = "_" + newName; + } + mChatInput->setText(inputText.substr(0, startName).append(newName) + .append(inputText.substr(caretPos, + inputText.length() - caretPos))); + + const int len = caretPos - static_cast(name.length()) + + static_cast(newName.length()); + + if (startName > 0) + mChatInput->setCaretPosition(len + 1); + else + mChatInput->setCaretPosition(len); + } +} + +std::string ChatWindow::autoComplete(StringVect &names, + std::string partName) const +{ + StringVectCIter i = names.begin(); + const StringVectCIter i_end = names.end(); + toLower(partName); + std::string newName; + + while (i != i_end) + { + if (!i->empty()) + { + std::string name = *i; + toLower(name); + + const size_t pos = name.find(partName, 0); + if (pos == 0) + { + if (!newName.empty()) + newName = findSameSubstringI(*i, newName); + else + newName = *i; + } + } + ++i; + } + + return newName; +} + +std::string ChatWindow::autoComplete(const std::string &partName, + History *const words) const +{ + if (!words) + return ""; + + ChatCommands::const_iterator i = words->begin(); + const ChatCommands::const_iterator i_end = words->end(); + StringVect nameList; + + while (i != i_end) + { + const std::string line = *i; + if (line.find(partName, 0) == 0) + nameList.push_back(line); + ++i; + } + return autoComplete(nameList, partName); +} + +/* +void ChatWindow::moveTabLeft(ChatTab *tab) +{ + mChatTabs->moveLeft(tab); +} + +void ChatWindow::moveTabRight(ChatTab *tab) +{ + mChatTabs->moveRight(tab); +} +*/ + +std::string ChatWindow::autoCompleteHistory(const std::string &partName) const +{ + History::const_iterator i = mHistory.begin(); + const History::const_iterator i_end = mHistory.end(); + StringVect nameList; + + while (i != i_end) + { + std::string line = *i; + unsigned int f = 0; + while (f < line.length() && !isWordSeparator(line.at(f))) + f++; + + line = line.substr(0, f); + if (line != "") + nameList.push_back(line); + + ++i; + } + return autoComplete(nameList, partName); +} + +void ChatWindow::resortChatLog(std::string line, Own own, + const std::string &channel, + const bool ignoreRecord, + const bool tryRemoveColors) +{ + if (own == -1) + own = BY_SERVER; + + std::string prefix; + if (!channel.empty()) + prefix = std::string("##3").append(channel).append("##0"); + + if (tradeChatTab) + { + if (findI(line, mTradeFilter) != std::string::npos) + { + tradeChatTab->chatLog(prefix + line, own, + ignoreRecord, tryRemoveColors); + return; + } + + size_t idx2 = line.find(": "); + if (idx2 != std::string::npos) + { + const size_t idx = line.find(": \302\202"); + if (idx == idx2) + { + // ignore special message formats. + if (line.find(": \302\202\302") != std::string::npos) + return; + line = line.erase(idx + 2, 2); + tradeChatTab->chatLog(prefix + line, own, ignoreRecord, + tryRemoveColors); + return; + } + } + + const size_t idx1 = line.find("@@"); + if (idx1 != std::string::npos) + { + idx2 = line.find("|", idx1); + if (idx2 != std::string::npos) + { + const size_t idx3 = line.find("@@", idx2); + if (idx3 != std::string::npos) + { + if (line.find("http", idx1) != idx1 + 2) + { + tradeChatTab->chatLog(prefix + line, own, + ignoreRecord, tryRemoveColors); + return; + } + } + } + } + } + + if (langChatTab && !channel.empty()) + { + if (langChatTab->getChannelName() == channel) + { + langChatTab->chatLog(line, own, ignoreRecord, tryRemoveColors); + } + else if (mShowAllLang) + { + if (langChatTab) + { + langChatTab->chatLog(prefix + line, own, + ignoreRecord, tryRemoveColors); + } + else if (localChatTab) + { + localChatTab->chatLog(prefix + line, own, + ignoreRecord, tryRemoveColors); + } + } + } + else if (localChatTab && channel.empty()) + { + localChatTab->chatLog(line, own, ignoreRecord, tryRemoveColors); + } +} + +void ChatWindow::battleChatLog(const std::string &line, Own own, + const bool ignoreRecord, + const bool tryRemoveColors) +{ + if (own == -1) + own = BY_SERVER; + if (battleChatTab) + battleChatTab->chatLog(line, own, ignoreRecord, tryRemoveColors); + else if (debugChatTab) + debugChatTab->chatLog(line, own, ignoreRecord, tryRemoveColors); +} + +void ChatWindow::initTradeFilter() +{ + const std::string tradeListName = client->getServerConfigDirectory() + + "/tradefilter.txt"; + + std::ifstream tradeFile; + struct stat statbuf; + + if (!stat(tradeListName.c_str(), &statbuf) && S_ISREG(statbuf.st_mode)) + { + tradeFile.open(tradeListName.c_str(), std::ios::in); + if (tradeFile.is_open()) + { + char line[100]; + while (tradeFile.getline(line, 100)) + { + const std::string str = line; + if (!str.empty()) + mTradeFilter.push_back(str); + } + } + tradeFile.close(); + } +} + +void ChatWindow::updateOnline(std::set &onlinePlayers) const +{ + const Party *party = nullptr; + const Guild *guild = nullptr; + if (player_node) + { + party = player_node->getParty(); + guild = player_node->getGuild(); + } + FOR_EACH (TabMap::const_iterator, iter, mWhispers) + { + if (!iter->second) + return; + + WhisperTab *const tab = static_cast(iter->second); + if (!tab) + continue; + + if (onlinePlayers.find(tab->getNick()) != onlinePlayers.end()) + { + tab->setWhisperTabColors(); + } + else + { + const std::string nick = tab->getNick(); + if (actorSpriteManager) + { + const Being *const being = actorSpriteManager->findBeingByName( + nick, ActorSprite::PLAYER); + if (being) + { + tab->setWhisperTabColors(); + continue; + } + } + if (party) + { + const PartyMember *const pm = party->getMember(nick); + if (pm && pm->getOnline()) + { + tab->setWhisperTabColors(); + continue; + } + } + if (guild) + { + const GuildMember *const gm = guild->getMember(nick); + if (gm && gm->getOnline()) + { + tab->setWhisperTabColors(); + continue; + } + } + tab->setWhisperTabOfflineColors(); + } + } +} + +void ChatWindow::loadState() +{ + int num = 0; + while (num < 50) + { + const std::string nick = serverConfig.getValue( + "chatWhisper" + toString(num), ""); + + if (nick.empty()) + break; + const int flags = serverConfig.getValue( + "chatWhisperFlags" + toString(num), 1); + + ChatTab *const tab = addWhisperTab(nick); + if (tab) + { + tab->setAllowHighlight(flags & 1); + tab->setRemoveNames((flags & 2) / 2); + tab->setNoAway((flags & 4) / 4); + } + num ++; + } +} + +void ChatWindow::saveState() const +{ + int num = 0; + for (TabMap::const_iterator iter = mWhispers.begin(), + iter_end = mWhispers.end(); iter != iter_end && num < 50; ++iter) + { + if (!iter->second) + return; + + const WhisperTab *const tab = static_cast(iter->second); + + if (!tab) + continue; + + serverConfig.setValue("chatWhisper" + toString(num), + tab->getNick()); + + serverConfig.setValue("chatWhisperFlags" + toString(num), + static_cast(tab->getAllowHighlight()) + + (2 * static_cast(tab->getRemoveNames())) + + (4 * static_cast(tab->getNoAway()))); + + num ++; + } + + while (num < 50) + { + serverConfig.deleteKey("chatWhisper" + toString(num)); + serverConfig.deleteKey("chatWhisperFlags" + toString(num)); + num ++; + } +} + +std::string ChatWindow::doReplace(const std::string &msg) const +{ + std::string str = msg; + replaceSpecialChars(str); + return str; +} + +void ChatWindow::loadCustomList() +{ + std::ifstream listFile; + struct stat statbuf; + + std::string listName = client->getServerConfigDirectory() + + "/customwords.txt"; + + if (!stat(listName.c_str(), &statbuf) && S_ISREG(statbuf.st_mode)) + { + listFile.open(listName.c_str(), std::ios::in); + if (listFile.is_open()) + { + char line[101]; + while (listFile.getline(line, 100)) + { + std::string str = line; + if (!str.empty()) + mCustomWords.push_back(str); + } + } + listFile.close(); + } +} + +void ChatWindow::addToAwayLog(const std::string &line) +{ + if (!player_node || !player_node->getAway()) + return; + + if (mAwayLog.size() > 20) + mAwayLog.pop_front(); + + if (findI(line, mHighlights) != std::string::npos) + mAwayLog.push_back("##9away:" + line); +} + +void ChatWindow::displayAwayLog() const +{ + if (!localChatTab) + return; + + std::list::const_iterator i = mAwayLog.begin(); + const std::list::const_iterator i_end = mAwayLog.end(); + + while (i != i_end) + { + std::string str = *i; + localChatTab->addNewRow(str); + ++i; + } +} + +void ChatWindow::parseHighlights() +{ + mHighlights.clear(); + if (!player_node) + return; + + splitToStringVector(mHighlights, config.getStringValue( + "highlightWords"), ','); + + mHighlights.push_back(player_node->getName()); +} + +void ChatWindow::parseGlobalsFilter() +{ + mGlobalsFilter.clear(); + if (!player_node) + return; + + splitToStringVector(mGlobalsFilter, config.getStringValue( + "globalsFilter"), ','); + + mHighlights.push_back(player_node->getName()); +} + +bool ChatWindow::findHighlight(const std::string &str) +{ + return findI(str, mHighlights) != std::string::npos; +} + +void ChatWindow::copyToClipboard(const int x, const int y) const +{ + const ChatTab *const tab = getFocused(); + if (!tab) + return; + + const BrowserBox *const text = tab->mTextOutput; + if (!text) + return; + + std::string str = text->getTextAtPos(x, y); + sendBuffer(str); +} + +void ChatWindow::optionChanged(const std::string &name) +{ + if (name == "autohideChat") + mAutoHide = config.getBoolValue("autohideChat"); + else if (name == "showBattleEvents") + mShowBattleEvents = config.getBoolValue("showBattleEvents"); + else if (name == "globalsFilter") + parseGlobalsFilter(); +} + +void ChatWindow::mouseMoved(gcn::MouseEvent &event) +{ + mHaveMouse = true; + Window::mouseMoved(event); +} + +void ChatWindow::mouseEntered(gcn::MouseEvent& mouseEvent) +{ + mHaveMouse = true; + Window::mouseEntered(mouseEvent); +} + +void ChatWindow::mouseExited(gcn::MouseEvent& mouseEvent) +{ + updateVisibility(); + Window::mouseExited(mouseEvent); +} + +void ChatWindow::draw(gcn::Graphics* graphics) +{ + BLOCK_START("ChatWindow::draw") + if (!mAutoHide || mHaveMouse) + Window::draw(graphics); + BLOCK_END("ChatWindow::draw") +} + +void ChatWindow::updateVisibility() +{ + int mouseX = 0; + int mouseY = 0; + int x = 0; + int y = 0; + SDL_GetMouseState(&mouseX, &mouseY); + getAbsolutePosition(x, y); + if (mChatInput->isVisible()) + { + mHaveMouse = true; + } + else + { + mHaveMouse = mouseX >= x && mouseX <= x + getWidth() + && mouseY >= y && mouseY <= y + getHeight(); + } +} + +void ChatWindow::unHideWindow() +{ + mHaveMouse = true; +} + +#ifdef USE_PROFILER +void ChatWindow::logicChildren() +{ + BLOCK_START("ChatWindow::logicChildren") + BasicContainer::logicChildren(); + BLOCK_END("ChatWindow::logicChildren") +} +#endif + +void ChatWindow::addGlobalMessage(const std::string &line) +{ + if (debugChatTab && findI(line, mGlobalsFilter) != std::string::npos) + debugChatTab->chatLog(line, BY_OTHER); + else + localChatTab->chatLog(line, BY_GM); +} diff --git a/src/gui/windows/chatwindow.h b/src/gui/windows/chatwindow.h new file mode 100644 index 000000000..7137af08f --- /dev/null +++ b/src/gui/windows/chatwindow.h @@ -0,0 +1,378 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_CHATWINDOW_H +#define GUI_CHATWINDOW_H + +#include "depricatedlistener.h" + +#include "configlistener.h" + +#include "utils/stringvector.h" + +#include "gui/widgets/window.h" + +#include +#include + +#include +#include +#include + +class ChatTab; +class ChatInput; +class ColorListModel; +class DropDown; +class TabbedArea; +class ItemLinkHandler; +class WhisperTab; + +const int DEFAULT_CHAT_WINDOW_SCROLL = 7; + +enum Own +{ + BY_GM = 0, + BY_PLAYER, + BY_OTHER, + BY_SERVER, + BY_CHANNEL, + ACT_WHISPER, // getting whispered at + ACT_IS, // equivalent to "/me" on IRC + BY_LOGGER, + BY_UNKNOWN = -1 +}; + +/** One item in the chat log */ +struct CHATLOG final +{ + CHATLOG() : + nick(), + text(), + own(BY_UNKNOWN) + { + } + + A_DELETE_COPY(CHATLOG) + + std::string nick; + std::string text; + Own own; +}; + +/** + * The chat window. + * + * \ingroup Interface + */ +class ChatWindow final : public Window, + public gcn::ActionListener, + public gcn::KeyListener, + public DepricatedListener, + public ConfigListener +{ + public: + /** + * Constructor. + */ + ChatWindow(); + + A_DELETE_COPY(ChatWindow) + + /** + * Destructor: used to write back values to the config file + */ + ~ChatWindow(); + + /** + * Gets the focused tab. + */ + ChatTab *getFocused() const A_WARN_UNUSED; + + /** + * Clear the given tab. + */ + void clearTab(ChatTab *const tab) const; + + /** + * Clear the current tab. + */ + void clearTab() const; + + /** + * Switch to the previous tab in order + */ + void prevTab(); + + /** + * Switch to the next tab in order + */ + void nextTab(); + + /** + * Close current chat tab + */ + void closeTab() const; + + /** + * Switch to the default tab + */ + void defaultTab(); + + /** + * Performs action. + */ + void action(const gcn::ActionEvent &event) override; + + /** + * Request focus for typing chat message. + * + * \returns true if the input was shown + * false otherwise + */ + bool requestChatFocus(); + + /** + * Checks whether ChatWindow is Focused or not. + */ + bool isInputFocused() const A_WARN_UNUSED; + + /** + * Passes the text to the current tab as input + * + * @param msg The message text which is to be sent. + */ + void chatInput(const std::string &msg) const; + + /** + * Passes the text to the local chat tab as input + * + * @param msg The message text which is to be sent. + */ + void localChatInput(const std::string &msg) const; + + /** Called when key is pressed */ + void keyPressed(gcn::KeyEvent &event) override; + + /** Set the chat input as the given text. */ + void setInputText(const std::string &text); + + /** Add the given text to the chat input. */ + void addInputText(const std::string &text, const bool space = true); + + /** Called to add item to chat */ + void addItemText(const std::string &item); + + /** Override to reset mTmpVisible */ + void setVisible(bool visible); + + /** + * Handles mouse when dragged. + */ + void mouseDragged(gcn::MouseEvent &event) override; + + /** + * Handles mouse when pressed. + */ + void mousePressed(gcn::MouseEvent &event) override; + + void processEvent(const Channels channel, + const DepricatedEvent &event) override; + + /** + * Scrolls the chat window + * + * @param amount direction and amount to scroll. Negative numbers scroll + * up, positive numbers scroll down. The absolute amount indicates the + * amount of 1/8ths of chat window real estate that should be scrolled. + */ + void scroll(const int amount) const; + + /** + * Sets the file being recorded to + * + * @param msg The file to write out to. If null, then stop recording. + */ + void setRecordingFile(const std::string &msg); + + bool getReturnTogglesChat() const A_WARN_UNUSED + { return mReturnToggles; } + + void setReturnTogglesChat(const bool toggles) + { mReturnToggles = toggles; } + + void doPresent() const; + + void addWhisper(const std::string &nick, const std::string &mes, + const Own own = BY_OTHER); + + WhisperTab *addWhisperTab(const std::string &nick, + const bool switchTo = false) A_WARN_UNUSED; + + WhisperTab *getWhisperTab(const std::string &nick) const A_WARN_UNUSED; + + void removeAllWhispers(); + + void ignoreAllWhispers(); + + void resortChatLog(std::string line, Own own, + const std::string &channel, + const bool ignoreRecord, + const bool tryRemoveColors); + + static void battleChatLog(const std::string &line, + Own own = BY_UNKNOWN, + const bool ignoreRecord = false, + const bool tryRemoveColors = true); + + void updateOnline(std::set &onlinePlayers) const; + + void loadState(); + + void saveState() const; + + void loadCustomList(); + + void loadGMCommands(); + + std::string doReplace(const std::string &msg) const A_WARN_UNUSED; + + void adjustTabSize(); + + void addToAwayLog(const std::string &line); + + void displayAwayLog() const; + + void clearAwayLog() + { mAwayLog.clear(); } + + void parseHighlights(); + + void parseGlobalsFilter(); + + bool findHighlight(const std::string &str) A_WARN_UNUSED; + + void copyToClipboard(const int x, const int y) const; + + void optionChanged(const std::string &name) override; + + void mouseEntered(gcn::MouseEvent& mouseEvent) override; + + void mouseMoved(gcn::MouseEvent &event) override; + + void mouseExited(gcn::MouseEvent& mouseEvent A_UNUSED) override; + + void draw(gcn::Graphics* graphics) override; + + void updateVisibility(); + + void unHideWindow(); + + void widgetResized(const gcn::Event &event) override; + + void addGlobalMessage(const std::string &line); + +#ifdef USE_PROFILER + void logicChildren(); +#endif + + protected: + friend class ChatTab; + friend class WhisperTab; + friend class PopupMenu; + + typedef std::list History; + + /** Remove the given tab from the window */ + void removeTab(ChatTab *const tab); + + /** Add the tab to the window */ + void addTab(ChatTab *const tab); + + void removeWhisper(const std::string &nick); + + void autoComplete(); + + std::string addColors(std::string &msg); + + std::string autoCompleteHistory(const std::string &partName) const; + + std::string autoComplete(const std::string &partName, + History *const words) const; + + std::string autoComplete(StringVect &names, + std::string partName) const; + + /** Used for showing item popup on clicking links **/ + ItemLinkHandler *mItemLinkHandler; + + /** Tabbed area for holding each channel. */ + TabbedArea *mChatTabs; + + /** Input box for typing chat messages. */ + ChatInput *mChatInput; + + void initTradeFilter(); + + int mRainbowColor; + + private: + void fillCommands(); + + void loadCommandsFile(const std::string &name); + + + typedef std::map TabMap; + /** Manage whisper tabs */ + TabMap mWhispers; + + typedef History::iterator HistoryIterator; + History mHistory; /**< Command history. */ + HistoryIterator mCurHist; /**< History iterator. */ + + typedef std::list ChatCommands; + typedef ChatCommands::iterator ChatCommandsIterator; + History mCommands; /**< Command list. */ + History mCustomWords; + + bool mReturnToggles; // Marks whether toggles the chat log + // or not + + StringVect mTradeFilter; + + ColorListModel *mColorListModel; + DropDown *mColorPicker; + int mChatColor; + unsigned int mChatHistoryIndex; + std::list mAwayLog; + StringVect mHighlights; + StringVect mGlobalsFilter; + bool mGMLoaded; + bool mHaveMouse; + bool mAutoHide; + bool mShowBattleEvents; + bool mShowAllLang; + bool mTmpVisible; +}; + +extern ChatWindow *chatWindow; + +#endif // GUI_CHATWINDOW_H diff --git a/src/gui/windows/confirmdialog.cpp b/src/gui/windows/confirmdialog.cpp new file mode 100644 index 000000000..34c54582c --- /dev/null +++ b/src/gui/windows/confirmdialog.cpp @@ -0,0 +1,109 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/confirmdialog.h" + +#include "soundmanager.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/textbox.h" + +#include "utils/gettext.h" + +#include + +#include "debug.h" + +ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg, + const std::string &soundEvent, const bool ignore, + const bool modal, Window *const parent): + Window(title, modal, parent, "confirm.xml"), + gcn::ActionListener(), + mTextBox(new TextBox(this)) +{ + mTextBox->setEditable(false); + mTextBox->setOpaque(false); + mTextBox->setTextWrapped(msg, 260); + + // TRANSLATORS: confirm dialog button + Button *const yesButton = new Button(this, _("Yes"), "yes", this); + // TRANSLATORS: confirm dialog button + Button *const noButton = new Button(this, _("No"), "no", this); + Button *const ignoreButton = ignore ? new Button( + // TRANSLATORS: confirm dialog button + this, _("Ignore"), "ignore", this) : nullptr; + + const int numRows = mTextBox->getNumberOfRows(); + int inWidth = yesButton->getWidth() + noButton->getWidth() + + (2 * mPadding); + + if (ignoreButton) + inWidth += ignoreButton->getWidth(); + + const int fontHeight = getFont()->getHeight(); + const int height = numRows * fontHeight; + int width = getFont()->getWidth(title); + + if (width < mTextBox->getMinWidth()) + width = mTextBox->getMinWidth(); + if (width < inWidth) + width = inWidth; + + setContentSize(mTextBox->getMinWidth() + fontHeight, height + fontHeight + + noButton->getHeight()); + mTextBox->setPosition(mPadding, mPadding); + + // 8 is the padding that GUIChan adds to button widgets + // (top and bottom combined) + const int buttonPadding = getOption("buttonPadding", 8); + yesButton->setPosition((width - inWidth) / 2, height + buttonPadding); + noButton->setPosition(yesButton->getX() + yesButton->getWidth() + + (2 * mPadding), height + buttonPadding); + if (ignoreButton) + { + ignoreButton->setPosition(noButton->getX() + noButton->getWidth() + + (2 * mPadding), height + buttonPadding); + } + + add(mTextBox); + add(yesButton); + add(noButton); + + if (ignore && ignoreButton) + add(ignoreButton); + + if (getParent()) + { + center(); + getParent()->moveToTop(this); + } + setVisible(true); + yesButton->requestFocus(); + soundManager.playGuiSound(soundEvent); +} + +void ConfirmDialog::action(const gcn::ActionEvent &event) +{ + setActionEventId(event.getId()); + distributeActionEvent(); + scheduleDelete(); +} diff --git a/src/gui/windows/confirmdialog.h b/src/gui/windows/confirmdialog.h new file mode 100644 index 000000000..76e3c2d18 --- /dev/null +++ b/src/gui/windows/confirmdialog.h @@ -0,0 +1,65 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_CONFIRMDIALOG_H +#define GUI_CONFIRMDIALOG_H + +#include "localconsts.h" + +#include "soundconsts.h" + +#include "gui/widgets/window.h" + +#include + +class TextBox; + +/** + * An option dialog. + * + * \ingroup GUI + */ +class ConfirmDialog : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor. + * + * @see Window::Window + */ + ConfirmDialog(const std::string &title, const std::string &msg, + const std::string &soundEvent = SOUND_REQUEST, + const bool ignore = false, const bool modal = false, + Window *const parent = nullptr); + + A_DELETE_COPY(ConfirmDialog) + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + private: + TextBox *mTextBox; +}; + +#endif // GUI_CONFIRMDIALOG_H diff --git a/src/gui/windows/connectiondialog.cpp b/src/gui/windows/connectiondialog.cpp new file mode 100644 index 000000000..cb03b5bbc --- /dev/null +++ b/src/gui/windows/connectiondialog.cpp @@ -0,0 +1,71 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/connectiondialog.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/label.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/progressindicator.h" + +#include "utils/gettext.h" + +#include "debug.h" + +ConnectionDialog::ConnectionDialog(const std::string &text, + const State cancelState): + Window(""), + gcn::ActionListener(), + mCancelState(cancelState) +{ + setTitleBarHeight(0); + setMovable(false); + setMinWidth(0); + + ProgressIndicator *const progressIndicator = new ProgressIndicator; + Label *const label = new Label(this, text); + Button *const cancelButton = new Button( + // TRANSLATORS: connection dialog button + this, _("Cancel"), "cancelButton", this); + + place(0, 0, progressIndicator); + place(0, 1, label); + place(0, 2, cancelButton).setHAlign(LayoutCell::CENTER); + reflowLayout(); + + center(); + setVisible(true); +} + +void ConnectionDialog::action(const gcn::ActionEvent &) +{ + logger->log1("Cancel pressed"); + client->setState(mCancelState); +} + +void ConnectionDialog::draw(gcn::Graphics *graphics) +{ + BLOCK_START("ConnectionDialog::draw") + // Don't draw the window background, only draw the children + drawChildren(graphics); + BLOCK_END("ConnectionDialog::draw") +} diff --git a/src/gui/windows/connectiondialog.h b/src/gui/windows/connectiondialog.h new file mode 100644 index 000000000..21f29712c --- /dev/null +++ b/src/gui/windows/connectiondialog.h @@ -0,0 +1,64 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_CONNECTIONDIALOG_H +#define GUI_CONNECTIONDIALOG_H + +#include "client.h" + +#include "gui/widgets/window.h" + +#include + +/** + * The connection dialog. + * + * \ingroup Interface + */ +class ConnectionDialog final : public Window, private gcn::ActionListener +{ + public: + /** + * Constructor. + * + * @param text The text to display + * @param cancelState The state to enter when Cancel is pressed + * + * @see Window::Window + */ + ConnectionDialog(const std::string &text, const State cancelState); + + A_DELETE_COPY(ConnectionDialog) + + /** + * Called when the user presses Cancel. Restores the global state to + * the previous one. + */ + void action(const gcn::ActionEvent &) override; + + void draw(gcn::Graphics *graphics) override; + + private: + State mCancelState; +}; + +#endif // GUI_CONNECTIONDIALOG_H diff --git a/src/gui/windows/debugwindow.cpp b/src/gui/windows/debugwindow.cpp new file mode 100644 index 000000000..0104af792 --- /dev/null +++ b/src/gui/windows/debugwindow.cpp @@ -0,0 +1,537 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/debugwindow.h" + +#include "client.h" +#include "game.h" +#include "main.h" + +#include "being/localplayer.h" + +#include "particle/particle.h" + +#include "gui/viewport.h" + +#include "gui/windows/setup.h" + +#include "gui/widgets/label.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/layouthelper.h" + +#include "resources/imagehelper.h" + +#include "net/packetcounters.h" + +#include "utils/gettext.h" + +#include "debug.h" + +DebugWindow::DebugWindow() : + // TRANSLATORS: debug window name + Window(_("Debug"), false, nullptr, "debug.xml"), + mTabs(new TabbedArea(this)), + mMapWidget(new MapDebugTab(this)), + mTargetWidget(new TargetDebugTab(this)), + mNetWidget(new NetDebugTab(this)) +{ + setWindowName("Debug"); + if (setupWindow) + setupWindow->registerWindowForReset(this); + + setResizable(true); + setCloseButton(true); + setSaveVisible(true); + setStickyButtonLock(true); + + setDefaultSize(400, 300, ImageRect::CENTER); + + // TRANSLATORS: debug window tab + mTabs->addTab(std::string(_("Map")), mMapWidget); + // TRANSLATORS: debug window tab + mTabs->addTab(std::string(_("Target")), mTargetWidget); + // TRANSLATORS: debug window tab + mTabs->addTab(std::string(_("Net")), mNetWidget); + + mTabs->setDimension(gcn::Rectangle(0, 0, 600, 300)); + add(mTabs); + + const int w = mDimension.width; + const int h = mDimension.height; + mMapWidget->resize(w, h); + mTargetWidget->resize(w, h); + mNetWidget->resize(w, h); + loadWindowState(); + enableVisibleSound(true); +} + +DebugWindow::~DebugWindow() +{ + delete mMapWidget; + mMapWidget = nullptr; + delete mTargetWidget; + mTargetWidget = nullptr; + delete mNetWidget; + mNetWidget = nullptr; +} + +void DebugWindow::slowLogic() +{ + BLOCK_START("DebugWindow::slowLogic") + if (!isWindowVisible() || !mTabs) + { + BLOCK_END("DebugWindow::slowLogic") + return; + } + + switch (mTabs->getSelectedTabIndex()) + { + default: + case 0: + mMapWidget->logic(); + break; + case 1: + mTargetWidget->logic(); + break; + case 2: + mNetWidget->logic(); + break; + } + + if (player_node) + player_node->tryPingRequest(); + BLOCK_END("DebugWindow::slowLogic") +} + +void DebugWindow::draw(gcn::Graphics *g) +{ + BLOCK_START("DebugWindow::draw") + Window::draw(g); + + if (player_node) + { + const Being *const target = player_node->getTarget(); + if (target) + { + Graphics *const g2 = static_cast(g); + target->draw(g2, -target->getPixelX() + 16 + mDimension.width / 2, + -target->getPixelY() + 32 + mDimension.height / 2); + } + } + BLOCK_END("DebugWindow::draw") +} + +void DebugWindow::widgetResized(const gcn::Event &event) +{ + Window::widgetResized(event); + + mTabs->setDimension(gcn::Rectangle(0, 0, + mDimension.width, mDimension.height)); +} + +#ifdef USE_PROFILER +void DebugWindow::logicChildren() +{ + BLOCK_START("DebugWindow::logicChildren") + BasicContainer::logicChildren(); + BLOCK_END("DebugWindow::logicChildren") +} +#endif + +MapDebugTab::MapDebugTab(const Widget2 *const widget) : + DebugTab(widget), + // TRANSLATORS: debug window label + mMusicFileLabel(new Label(this, strprintf(_("Music:")))), + // TRANSLATORS: debug window label + mMapLabel(new Label(this, strprintf(_("Map:")))), + // TRANSLATORS: debug window label + mMinimapLabel(new Label(this, strprintf(_("Minimap:")))), + mTileMouseLabel(new Label(this, strprintf("%s (%d, %d)", + // TRANSLATORS: debug window label + _("Cursor:"), 0, 0))), + mParticleCountLabel(new Label(this, strprintf("%s %d", + // TRANSLATORS: debug window label + _("Particle count:"), 88888))), + mMapActorCountLabel(new Label(this, strprintf("%s %d", + // TRANSLATORS: debug window label + _("Map actors count:"), 88888))), + // TRANSLATORS: debug window label + mXYLabel(new Label(this, strprintf("%s (?,?)", _("Player Position:")))), + mTexturesLabel(nullptr), + mUpdateTime(0), +#ifdef DEBUG_DRAW_CALLS + mDrawCallsLabel(new Label(this, strprintf("%s %s", + // TRANSLATORS: debug window label + _("Draw calls:"), "?"))), +#endif +#ifdef DEBUG_BIND_TEXTURE + mBindsLabel(new Label(this, strprintf("%s %s", + // TRANSLATORS: debug window label + _("Texture binds:"), "?"))), +#endif + // TRANSLATORS: debug window label, frames per second + mFPSLabel(new Label(this, strprintf(_("%d FPS"), 0))), + // TRANSLATORS: debug window label, logic per second + mLPSLabel(new Label(this, strprintf(_("%d LPS"), 0))), + mFPSText() +{ + LayoutHelper h(this); + ContainerPlacer place = h.getPlacer(0, 0); + +#ifdef USE_OPENGL + switch (imageHelper->useOpenGL()) + { + case RENDER_SOFTWARE: + // TRANSLATORS: debug window label + mFPSText = _("%d FPS (Software)"); + break; + case RENDER_NORMAL_OPENGL: + case RENDER_NULL: + case RENDER_LAST: + default: + // TRANSLATORS: debug window label + mFPSText = _("%d FPS (normal OpenGL)"); + break; + case RENDER_SAFE_OPENGL: + // TRANSLATORS: debug window label + mFPSText = _("%d FPS (safe OpenGL)"); + break; + case RENDER_GLES_OPENGL: + // TRANSLATORS: debug window label + mFPSText = _("%d FPS (mobile OpenGL)"); + break; + case RENDER_SDL2_DEFAULT: + // TRANSLATORS: debug window label + mFPSText = _("%d FPS (SDL2 default)"); + break; + }; +#else + // TRANSLATORS: debug window label + mFPSText = _("%d FPS (Software)"); +#endif + + place(0, 0, mFPSLabel, 2); + place(0, 1, mLPSLabel, 2); + place(0, 2, mMusicFileLabel, 2); + place(0, 3, mMapLabel, 2); + place(0, 4, mMinimapLabel, 2); + place(0, 5, mXYLabel, 2); + place(0, 6, mTileMouseLabel, 2); + place(0, 7, mParticleCountLabel, 2); + place(0, 8, mMapActorCountLabel, 2); +#ifdef USE_OPENGL +#if defined (DEBUG_OPENGL_LEAKS) || defined(DEBUG_DRAW_CALLS) \ + || defined(DEBUG_BIND_TEXTURE) + int n = 9; +#endif +#ifdef DEBUG_OPENGL_LEAKS + mTexturesLabel = new Label(this, strprintf("%s %s", + // TRANSLATORS: debug window label + _("Textures count:"), "?")); + place(0, n, mTexturesLabel, 2); + n ++; +#endif +#ifdef DEBUG_DRAW_CALLS + place(0, n, mDrawCallsLabel, 2); + n ++; +#endif +#ifdef DEBUG_BIND_TEXTURE + place(0, n, mBindsLabel, 2); +#endif +#endif + place.getCell().matchColWidth(0, 0); + place = h.getPlacer(0, 1); + setDimension(gcn::Rectangle(0, 0, 600, 300)); +} + +void MapDebugTab::logic() +{ + if (player_node) + { + // TRANSLATORS: debug window label + mXYLabel->setCaption(strprintf("%s (%d, %d)", _("Player Position:"), + player_node->getTileX(), player_node->getTileY())); + } + else + { + // TRANSLATORS: debug window label + mXYLabel->setCaption(strprintf("%s (?, ?)", _("Player Position:"))); + } + + const Map *const map = Game::instance()->getCurrentMap(); + if (map && viewport) + { + // Get the current mouse position + const int mouseTileX = (viewport->getMouseX() + viewport->getCameraX()) + / map->getTileWidth(); + const int mouseTileY = (viewport->getMouseY() + viewport->getCameraY()) + / map->getTileHeight(); + mTileMouseLabel->setCaption(strprintf("%s (%d, %d)", + // TRANSLATORS: debug window label + _("Cursor:"), mouseTileX, mouseTileY)); + + // TRANSLATORS: debug window label + mMusicFileLabel->setCaption(strprintf("%s %s", _("Music:"), + map->getProperty("music").c_str())); + // TRANSLATORS: debug window label + mMinimapLabel->setCaption(strprintf("%s %s", _("Minimap:"), + map->getProperty("minimap").c_str())); + // TRANSLATORS: debug window label + mMapLabel->setCaption(strprintf("%s %s", _("Map:"), + map->getProperty("_realfilename").c_str())); + + + if (mUpdateTime != cur_time) + { + mUpdateTime = cur_time; + // TRANSLATORS: debug window label + mParticleCountLabel->setCaption(strprintf(_("Particle count: %d"), + Particle::particleCount)); + + mMapActorCountLabel->setCaption( + // TRANSLATORS: debug window label + strprintf("%s %d", _("Map actors count:"), + map->getActorsCount())); +#ifdef USE_OPENGL +#ifdef DEBUG_OPENGL_LEAKS + mTexturesLabel->setCaption(strprintf("%s %d", + // TRANSLATORS: debug window label + _("Textures count:"), textures_count)); +#endif +#ifdef DEBUG_DRAW_CALLS + if (mainGraphics) + { + mDrawCallsLabel->setCaption(strprintf("%s %d", + // TRANSLATORS: debug window label + _("Draw calls:"), mainGraphics->getDrawCalls())); + } +#endif +#ifdef DEBUG_BIND_TEXTURE + if (mainGraphics) + { + mBindsLabel->setCaption(strprintf("%s %d", + // TRANSLATORS: debug window label + _("Texture binds:"), mainGraphics->getBinds())); + } +#endif +#endif + } + } + else + { + // TRANSLATORS: debug window label + mTileMouseLabel->setCaption(strprintf("%s (?, ?)", _("Cursor:"))); + // TRANSLATORS: debug window label + mMusicFileLabel->setCaption(strprintf("%s ?", _("Music:"))); + // TRANSLATORS: debug window label + mMinimapLabel->setCaption(strprintf("%s ?", _("Minimap:"))); + // TRANSLATORS: debug window label + mMapLabel->setCaption(strprintf("%s ?", _("Map:"))); + + mMapActorCountLabel->setCaption( + // TRANSLATORS: debug window label + strprintf("%s ?", _("Map actors count:"))); + } + + mMapActorCountLabel->adjustSize(); + mParticleCountLabel->adjustSize(); + + mFPSLabel->setCaption(strprintf(mFPSText.c_str(), fps)); + // TRANSLATORS: debug window label, logic per second + mLPSLabel->setCaption(strprintf(_("%d LPS"), lps)); +} + +TargetDebugTab::TargetDebugTab(const Widget2 *const widget) : + DebugTab(widget), + // TRANSLATORS: debug window label + mTargetLabel(new Label(this, strprintf("%s ?", _("Target:")))), + // TRANSLATORS: debug window label + mTargetIdLabel(new Label(this, strprintf("%s ? ", _("Target Id:")))), + mTargetTypeLabel(new Label(this, strprintf( + // TRANSLATORS: debug window label + "%s ? ", _("Target type:")))), + // TRANSLATORS: debug window label + mTargetLevelLabel(new Label(this, strprintf("%s ?", _("Target level:")))), + // TRANSLATORS: debug window label + mTargetRaceLabel(new Label(this, strprintf("%s ?", _("Target race:")))), + // TRANSLATORS: debug window label + mTargetPartyLabel(new Label(this, strprintf("%s ?", _("Target party:")))), + // TRANSLATORS: debug window label + mTargetGuildLabel(new Label(this, strprintf("%s ?", _("Target guild:")))), + // TRANSLATORS: debug window label + mAttackDelayLabel(new Label(this, strprintf("%s ?", _("Attack delay:")))), + // TRANSLATORS: debug window label + mMinHitLabel(new Label(this, strprintf("%s ?", _("Minimal hit:")))), + // TRANSLATORS: debug window label + mMaxHitLabel(new Label(this, strprintf("%s ?", _("Maximum hit:")))), + // TRANSLATORS: debug window label + mCriticalHitLabel(new Label(this, strprintf("%s ?", _("Critical hit:")))) +{ + LayoutHelper h(this); + ContainerPlacer place = h.getPlacer(0, 0); + + place(0, 0, mTargetLabel, 2); + place(0, 1, mTargetIdLabel, 2); + place(0, 2, mTargetTypeLabel, 2); + place(0, 3, mTargetLevelLabel, 2); + place(0, 4, mTargetRaceLabel, 2); + place(0, 5, mAttackDelayLabel, 2); + place(0, 6, mTargetPartyLabel, 2); + place(0, 7, mTargetGuildLabel, 2); + place(0, 8, mMinHitLabel, 2); + place(0, 9, mMaxHitLabel, 2); + place(0, 10, mCriticalHitLabel, 2); + + place.getCell().matchColWidth(0, 0); + place = h.getPlacer(0, 1); + setDimension(gcn::Rectangle(0, 0, 600, 300)); +} + +void TargetDebugTab::logic() +{ + if (player_node && player_node->getTarget()) + { + const Being *const target = player_node->getTarget(); + + // TRANSLATORS: debug window label + mTargetLabel->setCaption(strprintf("%s %s (%d, %d)", _("Target:"), + target->getName().c_str(), target->getTileX(), + target->getTileY())); + + mTargetIdLabel->setCaption(strprintf("%s %d", + // TRANSLATORS: debug window label + _("Target Id:"), target->getId())); + mTargetTypeLabel->setCaption(strprintf("%s %d", + // TRANSLATORS: debug window label + _("Target type:"), target->getSubType())); + if (target->getLevel()) + { + mTargetLevelLabel->setCaption(strprintf("%s %d", + // TRANSLATORS: debug window label + _("Target Level:"), target->getLevel())); + } + else + { + mTargetLevelLabel->setCaption(strprintf("%s ?", + // TRANSLATORS: debug window label + _("Target Level:"))); + } + + mTargetRaceLabel->setCaption(strprintf("%s %s", + // TRANSLATORS: debug window label + _("Target race:"), target->getRaceName().c_str())); + + // TRANSLATORS: debug window label + mTargetPartyLabel->setCaption(strprintf("%s %s", _("Target Party:"), + target->getPartyName().c_str())); + + // TRANSLATORS: debug window label + mTargetGuildLabel->setCaption(strprintf("%s %s", _("Target Guild:"), + target->getGuildName().c_str())); + + mMinHitLabel->setCaption(strprintf("%s %d", + // TRANSLATORS: debug window label + _("Minimal hit:"), target->getMinHit())); + mMaxHitLabel->setCaption(strprintf("%s %d", + // TRANSLATORS: debug window label + _("Maximum hit:"), target->getMaxHit())); + mCriticalHitLabel->setCaption(strprintf("%s %d", + // TRANSLATORS: debug window label + _("Critical hit:"), target->getCriticalHit())); + + const int delay = target->getAttackDelay(); + if (delay) + { + mAttackDelayLabel->setCaption(strprintf("%s %d", + // TRANSLATORS: debug window label + _("Attack delay:"), delay)); + } + else + { + mAttackDelayLabel->setCaption(strprintf( + // TRANSLATORS: debug window label + "%s ?", _("Attack delay:"))); + } + } + else + { + // TRANSLATORS: debug window label + mTargetLabel->setCaption(strprintf("%s ?", _("Target:"))); + // TRANSLATORS: debug window label + mTargetIdLabel->setCaption(strprintf("%s ?", _("Target Id:"))); + // TRANSLATORS: debug window label + mTargetTypeLabel->setCaption(strprintf("%s ?", _("Target type:"))); + // TRANSLATORS: debug window label + mTargetLevelLabel->setCaption(strprintf("%s ?", _("Target Level:"))); + // TRANSLATORS: debug window label + mTargetPartyLabel->setCaption(strprintf("%s ?", _("Target Party:"))); + // TRANSLATORS: debug window label + mTargetGuildLabel->setCaption(strprintf("%s ?", _("Target Guild:"))); + // TRANSLATORS: debug window label + mAttackDelayLabel->setCaption(strprintf("%s ?", _("Attack delay:"))); + // TRANSLATORS: debug window label + mMinHitLabel->setCaption(strprintf("%s ?", _("Minimal hit:"))); + // TRANSLATORS: debug window label + mMaxHitLabel->setCaption(strprintf("%s ?", _("Maximum hit:"))); + // TRANSLATORS: debug window label + mCriticalHitLabel->setCaption(strprintf("%s ?", _("Critical hit:"))); + } + + mTargetLabel->adjustSize(); + mTargetIdLabel->adjustSize(); + mTargetTypeLabel->adjustSize(); + mTargetLevelLabel->adjustSize(); + mTargetPartyLabel->adjustSize(); + mTargetGuildLabel->adjustSize(); + mAttackDelayLabel->adjustSize(); +} + +NetDebugTab::NetDebugTab(const Widget2 *const widget) : + DebugTab(widget), + mPingLabel(new Label(this, " ")), + mInPackets1Label(new Label(this, " ")), + mOutPackets1Label(new Label(this, " ")) +{ + LayoutHelper h(this); + ContainerPlacer place = h.getPlacer(0, 0); + + place(0, 0, mPingLabel, 2); + place(0, 1, mInPackets1Label, 2); + place(0, 2, mOutPackets1Label, 2); + + place.getCell().matchColWidth(0, 0); + place = h.getPlacer(0, 1); + setDimension(gcn::Rectangle(0, 0, 600, 300)); +} + +void NetDebugTab::logic() +{ + // TRANSLATORS: debug window label + mPingLabel->setCaption(strprintf(_("Ping: %s ms"), + player_node->getPingTime().c_str())); + // TRANSLATORS: debug window label + mInPackets1Label->setCaption(strprintf(_("In: %d bytes/s"), + PacketCounters::getInBytes())); + // TRANSLATORS: debug window label + mOutPackets1Label->setCaption(strprintf(_("Out: %d bytes/s"), + PacketCounters::getOutBytes())); +} diff --git a/src/gui/windows/debugwindow.h b/src/gui/windows/debugwindow.h new file mode 100644 index 000000000..ef67df432 --- /dev/null +++ b/src/gui/windows/debugwindow.h @@ -0,0 +1,165 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_DEBUGWINDOW_H +#define GUI_DEBUGWINDOW_H + +#include "gui/widgets/container.h" +#include "gui/widgets/window.h" + +class Label; +class TabbedArea; + +class DebugTab : public Container +{ + friend class DebugWindow; + + public: + A_DELETE_COPY(DebugTab) + + void logic() override = 0; + + void resize(const int x, const int y) + { setDimension(gcn::Rectangle(0, 0, x, y)); } + + protected: + explicit DebugTab(const Widget2 *const widget) : + Container(widget) + { } +}; + +class MapDebugTab final : public DebugTab +{ + friend class DebugWindow; + + public: + explicit MapDebugTab(const Widget2 *const widget); + + A_DELETE_COPY(MapDebugTab) + + void logic() override; + + private: + Label *mMusicFileLabel; + Label *mMapLabel; + Label *mMinimapLabel; + Label *mTileMouseLabel; + Label *mParticleCountLabel; + Label *mMapActorCountLabel; + Label *mXYLabel; + Label *mTexturesLabel; + int mUpdateTime; +#ifdef DEBUG_DRAW_CALLS + Label *mDrawCallsLabel; +#endif +#ifdef DEBUG_BIND_TEXTURE + Label *mBindsLabel; +#endif + Label *mFPSLabel; + Label *mLPSLabel; + std::string mFPSText; +}; + +class TargetDebugTab final : public DebugTab +{ + friend class DebugWindow; + + public: + explicit TargetDebugTab(const Widget2 *const widget); + + A_DELETE_COPY(TargetDebugTab) + + void logic() override; + + private: + Label *mTargetLabel; + Label *mTargetIdLabel; + Label *mTargetTypeLabel; + Label *mTargetLevelLabel; + Label *mTargetRaceLabel; + Label *mTargetPartyLabel; + Label *mTargetGuildLabel; + Label *mAttackDelayLabel; + Label *mMinHitLabel; + Label *mMaxHitLabel; + Label *mCriticalHitLabel; +}; + +class NetDebugTab final : public DebugTab +{ + friend class DebugWindow; + + public: + explicit NetDebugTab(const Widget2 *const widget); + + A_DELETE_COPY(NetDebugTab) + + void logic() override; + + private: + Label *mPingLabel; + Label *mInPackets1Label; + Label *mOutPackets1Label; +}; + +/** + * The debug window. + * + * \ingroup Interface + */ +class DebugWindow final : public Window +{ + public: + /** + * Constructor. + */ + DebugWindow(); + + A_DELETE_COPY(DebugWindow) + + ~DebugWindow(); + + /** + * Logic (updates components' size and infos) + */ + void slowLogic(); + + void draw(gcn::Graphics *g) override; + + void setPing(int pingTime); + + void widgetResized(const gcn::Event &event) override; + +#ifdef USE_PROFILER + void logicChildren(); +#endif + + private: + TabbedArea *mTabs; + MapDebugTab *mMapWidget; + TargetDebugTab *mTargetWidget; + NetDebugTab *mNetWidget; +}; + +extern DebugWindow *debugWindow; + +#endif // GUI_DEBUGWINDOW_H diff --git a/src/gui/windows/didyouknowwindow.cpp b/src/gui/windows/didyouknowwindow.cpp new file mode 100644 index 000000000..8c900d119 --- /dev/null +++ b/src/gui/windows/didyouknowwindow.cpp @@ -0,0 +1,177 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/didyouknowwindow.h" + +#include "configuration.h" + +#include "gui/gui.h" +#include "gui/sdlfont.h" + +#include "gui/windows/setup.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/browserbox.h" +#include "gui/widgets/checkbox.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/scrollarea.h" + +#include "utils/gettext.h" +#include "utils/process.h" + +#include "utils/translation/podict.h" +#include "utils/translation/translationmanager.h" + +#include "debug.h" + +static const int minTip = 1; +static const int maxTip = 18; + +DidYouKnowWindow::DidYouKnowWindow() : + // TRANSLATORS: did you know window name + Window(_("Did You Know?"), false, nullptr, "didyouknow.xml"), + gcn::ActionListener(), + mBrowserBox(new BrowserBox(this)), + mScrollArea(new ScrollArea(mBrowserBox, + true, "didyouknow_background.xml")), + // TRANSLATORS: did you know window button + mButtonPrev(new Button(this, _("< Previous"), "prev", this)), + // TRANSLATORS: did you know window button + mButtonNext(new Button(this, _("Next >"), "next", this)), + // TRANSLATORS: did you know window checkbox + mOpenAgainCheckBox(new CheckBox(this, _("Auto open this window"), + config.getBoolValue("showDidYouKnow"), this, "openagain")) +{ + setMinWidth(300); + setMinHeight(220); + setContentSize(455, 350); + setWindowName("DidYouKnow"); + setCloseButton(true); + setResizable(true); + setStickyButtonLock(true); + + if (setupWindow) + setupWindow->registerWindowForReset(this); + setDefaultSize(500, 400, ImageRect::CENTER); + + mBrowserBox->setOpaque(false); + // TRANSLATORS: did you know window button + Button *const okButton = new Button(this, _("Close"), "close", this); + + mBrowserBox->setLinkHandler(this); + mBrowserBox->setFont(gui->getHelpFont()); + mBrowserBox->setProcessVersion(true); + mBrowserBox->setEnableImages(true); + mBrowserBox->setEnableKeys(true); + mBrowserBox->setEnableTabs(true); + + place(0, 0, mScrollArea, 5, 3).setPadding(3); + place(0, 3, mOpenAgainCheckBox, 5); + place(1, 4, mButtonPrev, 1); + place(2, 4, mButtonNext, 1); + place(4, 4, okButton); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + + loadWindowState(); + enableVisibleSound(true); + widgetResized(gcn::Event(nullptr)); +} + +void DidYouKnowWindow::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "close") + { + setVisible(false); + } + else + { + const unsigned num = config.getIntValue("currentTip"); + if (eventId == "prev") + { + loadData(num - 1); + } + else if (eventId == "next") + { + loadData(num + 1); + } + else if (eventId == "openagain") + { + config.setValue("showDidYouKnow", + mOpenAgainCheckBox->isSelected()); + } + } +} + +void DidYouKnowWindow::handleLink(const std::string &link, + gcn::MouseEvent *event A_UNUSED) +{ + if (strStartWith(link, "http://") || strStartWith(link, "https://")) + openBrowser(link); +} + +void DidYouKnowWindow::loadData(int num) +{ + mBrowserBox->clearRows(); + if (!num) + { + const int curTip = config.getIntValue("currentTip"); + if (curTip == 1) + num = maxTip; + else + num = curTip + 1; + } + + if (num < minTip || num > maxTip) + num = minTip; + + config.setValue("currentTip", num); + + loadFile(num); + + mScrollArea->setVerticalScrollAmount(0); +} + +void DidYouKnowWindow::loadFile(const int num) +{ + const std::string file = strprintf("tips/%d", num); + std::string helpPath = branding.getStringValue("helpPath"); + if (helpPath.empty()) + helpPath = paths.getStringValue("help"); + + StringVect lines; + TranslationManager::translateFile(helpPath.append(file).append(".txt"), + translator, lines); + + for (size_t i = 0, sz = lines.size(); i < sz; ++i) + mBrowserBox->addRow(lines[i]); +} + +void DidYouKnowWindow::setVisible(bool visible) +{ + Window::setVisible(visible); + + if (visible || isWindowVisible()) + loadData(); +} diff --git a/src/gui/windows/didyouknowwindow.h b/src/gui/windows/didyouknowwindow.h new file mode 100644 index 000000000..49cb07a8b --- /dev/null +++ b/src/gui/windows/didyouknowwindow.h @@ -0,0 +1,78 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_DIDYOUKNOWWINDOW_H +#define GUI_DIDYOUKNOWWINDOW_H + +#include "gui/widgets/linkhandler.h" +#include "gui/widgets/window.h" + +#include + +class Button; +class BrowserBox; +class CheckBox; +class ScrollArea; + +/** + * The help dialog. + */ +class DidYouKnowWindow final : public Window, + public LinkHandler, + public gcn::ActionListener +{ + public: + /** + * Constructor. + */ + DidYouKnowWindow(); + + A_DELETE_COPY(DidYouKnowWindow) + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + /** + * Handles link action. + */ + void handleLink(const std::string &link, + gcn::MouseEvent *event) override; + + void loadData(int num = 0); + + void setVisible(bool visible); + + private: + void loadFile(const int num); + + BrowserBox *mBrowserBox; + ScrollArea *mScrollArea; + Button *mButtonPrev; + Button *mButtonNext; + CheckBox *mOpenAgainCheckBox; +}; + +extern DidYouKnowWindow *didYouKnowWindow; + +#endif // GUI_DIDYOUKNOWWINDOW_H diff --git a/src/gui/windows/editdialog.cpp b/src/gui/windows/editdialog.cpp new file mode 100644 index 000000000..acd5d9f72 --- /dev/null +++ b/src/gui/windows/editdialog.cpp @@ -0,0 +1,72 @@ +/* + * The ManaPlus Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 Andrei Karas + * Copyright (C) 2011-2013 The ManaPlus developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/editdialog.h" + +#include "gui/widgets/button.h" + +#include "utils/gettext.h" + +#include + +#include "debug.h" + +EditDialog::EditDialog(const std::string &title, const std::string &msg, + const std::string &eventOk, const int width, + Window *const parent, const bool modal): + Window(title, modal, parent, "edit.xml"), + gcn::ActionListener(), + mEventOk(eventOk), + mTextField(new TextField(this)) +{ + mTextField->setText(msg); + // TRANSLATORS: edit dialog label + Button *const okButton = new Button(this, _("OK"), mEventOk, this); + + const int numRows = 1; + const int fontHeight = getFont()->getHeight(); + const int height = numRows * fontHeight; + + setContentSize(width, height + fontHeight + okButton->getHeight()); + mTextField->setPosition(getPadding(), getPadding()); + mTextField->setWidth(width - (2 * getPadding())); + + okButton->setPosition((width - okButton->getWidth()) / 2, + height + getOption("buttonPadding", 8)); + + add(mTextField); + add(okButton); + + center(); + setVisible(true); + okButton->requestFocus(); +} + +void EditDialog::action(const gcn::ActionEvent &event) +{ + // Proxy button events to our listeners + FOR_EACH (ActionListenerIterator, i, mActionListeners) + (*i)->action(event); + + if (event.getId() == mEventOk) + scheduleDelete(); +} diff --git a/src/gui/windows/editdialog.h b/src/gui/windows/editdialog.h new file mode 100644 index 000000000..6d3d191bc --- /dev/null +++ b/src/gui/windows/editdialog.h @@ -0,0 +1,69 @@ +/* + * The ManaPlus Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 Andrei Karas + * Copyright (C) 2011-2013 The ManaPlus developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_EDITDIALOG_H +#define GUI_EDITDIALOG_H + +#include "localconsts.h" + +#include "gui/widgets/window.h" +#include "gui/widgets/textfield.h" + +#include + +#define ACTION_EDIT_OK "edit ok" + +/** + * An 'Ok' button dialog. + * + * \ingroup GUI + */ +class EditDialog final : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor. + * + * @see Window::Window + */ + EditDialog(const std::string &title, const std::string &msg, + const std::string &eventOk = ACTION_EDIT_OK, + const int width = 300, Window *const parent = nullptr, + const bool modal = true); + + A_DELETE_COPY(EditDialog) + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + std::string getMsg() const A_WARN_UNUSED + { return mTextField->getText(); } + + private: + std::string mEventOk; + + TextField *mTextField; +}; + +#endif // GUI_EDITDIALOG_H diff --git a/src/gui/windows/editserverdialog.cpp b/src/gui/windows/editserverdialog.cpp new file mode 100644 index 000000000..2a6814525 --- /dev/null +++ b/src/gui/windows/editserverdialog.cpp @@ -0,0 +1,300 @@ +/* + * The Mana Client + * Copyright (C) 2011-2012 The Mana Developers + * Copyright (C) 2012-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/editserverdialog.h" + +#include "input/keydata.h" +#include "input/keyevent.h" + +#include "gui/windows/okdialog.h" +#include "gui/windows/serverdialog.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/dropdown.h" +#include "gui/widgets/label.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/textfield.h" + +#include "utils/gettext.h" + +std::string TypeListModel::getElementAt(int elementIndex) +{ + if (elementIndex == 0) + return "TmwAthena"; + else if (elementIndex == 1) + return "Evol"; +#ifdef EATHENA_SUPPORT + else if (elementIndex == 2) + return "eAthena"; +#ifdef MANASERV_SUPPORT + else if (elementIndex == 3) + return "ManaServ"; +#endif +#else +#ifdef MANASERV_SUPPORT + else if (elementIndex == 2) + return "ManaServ"; +#endif +#endif + else + return "Unknown"; +} + +EditServerDialog::EditServerDialog(ServerDialog *const parent, + ServerInfo server, + const int index) : + // TRANSLATORS: edit server dialog name + Window(_("Edit Server"), true, parent), + gcn::ActionListener(), + gcn::KeyListener(), + mServerAddressField(new TextField(this, std::string())), + mPortField(new TextField(this, std::string())), + mNameField(new TextField(this, std::string())), + mDescriptionField(new TextField(this, std::string())), + mOnlineListUrlField(new TextField(this, std::string())), + // TRANSLATORS: edit server dialog button + mConnectButton(new Button(this, _("Connect"), "connect", this)), + // TRANSLATORS: edit server dialog button + mOkButton(new Button(this, _("OK"), "addServer", this)), + // TRANSLATORS: edit server dialog button + mCancelButton(new Button(this, _("Cancel"), "cancel", this)), + mTypeListModel(new TypeListModel), + mTypeField(new DropDown(this, mTypeListModel, false, true)), + mServerDialog(parent), + mServer(server), + mIndex(index) +{ + setWindowName("EditServerDialog"); + + // TRANSLATORS: edit server dialog label + Label *const nameLabel = new Label(this, _("Name:")); + // TRANSLATORS: edit server dialog label + Label *const serverAdressLabel = new Label(this, _("Address:")); + // TRANSLATORS: edit server dialog label + Label *const portLabel = new Label(this, _("Port:")); + // TRANSLATORS: edit server dialog label + Label *const typeLabel = new Label(this, _("Server type:")); + // TRANSLATORS: edit server dialog label + Label *const descriptionLabel = new Label(this, _("Description:")); + // TRANSLATORS: edit server dialog label + Label *const onlineListUrlLabel = new Label(this, _("Online list url:")); + mPortField->setNumeric(true); + mPortField->setRange(1, 65535); + + mTypeField->setSelected(0); // TmwAthena by default + + mServerAddressField->addActionListener(this); + mPortField->addActionListener(this); + + place(0, 0, nameLabel); + place(1, 0, mNameField, 4).setPadding(3); + place(0, 1, serverAdressLabel); + place(1, 1, mServerAddressField, 4).setPadding(3); + place(0, 2, portLabel); + place(1, 2, mPortField, 4).setPadding(3); + place(0, 3, typeLabel); + place(1, 3, mTypeField).setPadding(3); + place(0, 4, descriptionLabel); + place(1, 4, mDescriptionField, 4).setPadding(3); + place(0, 5, onlineListUrlLabel); + place(1, 5, mOnlineListUrlField, 4).setPadding(3); + place(0, 6, mConnectButton); + place(4, 6, mOkButton); + place(3, 6, mCancelButton); + + // Do this manually instead of calling reflowLayout so we can enforce a + // minimum width. + int width = 0; + int height = 0; + getLayout().reflow(width, height); + if (width < 300) + { + width = 300; + getLayout().reflow(width, height); + } + if (height < 120) + { + height = 120; + getLayout().reflow(width, height); + } + + setContentSize(width, height); + + setMinWidth(getWidth()); + setMinHeight(getHeight()); + setDefaultSize(getWidth(), getHeight(), ImageRect::CENTER); + + setResizable(false); + addKeyListener(this); + + loadWindowState(); + + mNameField->setText(mServer.name); + mDescriptionField->setText(mServer.description); + mOnlineListUrlField->setText(mServer.onlineListUrl); + mServerAddressField->setText(mServer.hostname); + mPortField->setText(toString(mServer.port)); + + switch (mServer.type) + { +#ifdef EATHENA_SUPPORT + case ServerInfo::EATHENA: + mTypeField->setSelected(2); + break; + case ServerInfo::MANASERV: +#ifdef MANASERV_SUPPORT + mTypeField->setSelected(3); + break; +#endif +#else + case ServerInfo::MANASERV: +#ifdef MANASERV_SUPPORT + mTypeField->setSelected(2); + break; +#endif +#endif + default: + case ServerInfo::UNKNOWN: + case ServerInfo::TMWATHENA: +#ifndef EATHENA_SUPPORT + case ServerInfo::EATHENA: +#endif + mTypeField->setSelected(0); + break; + case ServerInfo::EVOL: + mTypeField->setSelected(1); + break; + } + + setLocationRelativeTo(getParentWindow()); + setVisible(true); + + mNameField->requestFocus(); +} + +EditServerDialog::~EditServerDialog() +{ + delete mTypeListModel; +} + +void EditServerDialog::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + + if (eventId == "ok") + { + // Give focus back to the server dialog. + mServerAddressField->requestFocus(); + } + if (eventId == "addServer" || eventId == "connect") + { + // Check the given information + if (mServerAddressField->getText().empty() + || mPortField->getText().empty()) + { + // TRANSLATORS: edit server dialog error header + OkDialog *const dlg = new OkDialog(_("Error"), + // TRANSLATORS: edit server dialog error message + _("Please at least type both the address and the port " + "of the server."), DIALOG_ERROR); + dlg->addActionListener(this); + } + else + { + mCancelButton->setEnabled(false); + mOkButton->setEnabled(false); + + mServer.name = mNameField->getText(); + mServer.description = mDescriptionField->getText(); + mServer.onlineListUrl = mOnlineListUrlField->getText(); + mServer.hostname = mServerAddressField->getText(); + mServer.port = static_cast(atoi( + mPortField->getText().c_str())); + + if (mTypeField) + { + switch (mTypeField->getSelected()) + { + case 0: + mServer.type = ServerInfo::TMWATHENA; + break; + case 1: + mServer.type = ServerInfo::EVOL; + break; +#ifdef EATHENA_SUPPORT + case 2: + mServer.type = ServerInfo::EATHENA; + break; +#ifdef MANASERV_SUPPORT + case 3: + mServer.type = ServerInfo::MANASERV; + break; +#endif +#else +#ifdef MANASERV_SUPPORT + case 2: + mServer.type = ServerInfo::MANASERV; + break; +#endif +#endif + default: + mServer.type = ServerInfo::UNKNOWN; + } + } + else + { + mServer.type = ServerInfo::TMWATHENA; + } + + // Tell the server has to be saved + mServer.save = true; + + // Add server + mServerDialog->updateServer(mServer, mIndex); + if (eventId == "connect") + mServerDialog->connectToSelectedServer(); + scheduleDelete(); + } + } + else if (eventId == "cancel") + { + scheduleDelete(); + } +} + +void EditServerDialog::keyPressed(gcn::KeyEvent &keyEvent) +{ + if (keyEvent.isConsumed()) + return; + + const int actionId = static_cast( + &keyEvent)->getActionId(); + + if (actionId == static_cast(Input::KEY_GUI_CANCEL)) + { + scheduleDelete(); + } + else if (actionId == static_cast(Input::KEY_GUI_SELECT) + || actionId == static_cast(Input::KEY_GUI_SELECT2)) + { + action(gcn::ActionEvent(nullptr, mOkButton->getActionEventId())); + } +} diff --git a/src/gui/windows/editserverdialog.h b/src/gui/windows/editserverdialog.h new file mode 100644 index 000000000..531bb009a --- /dev/null +++ b/src/gui/windows/editserverdialog.h @@ -0,0 +1,113 @@ +/* + * The Mana Client + * Copyright (C) 2011-2012 The Mana Developers + * Copyright (C) 2012-2013 The ManaPlus Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_EDITSERVERDIALOG_H +#define GUI_EDITSERVERDIALOG_H + +class Button; +class TextField; +class DropDown; +class ServerDialog; + +#include "gui/widgets/window.h" + +#include "net/serverinfo.h" + +#include +#include +#include + +/** + * Server Type List Model + */ +class TypeListModel : public gcn::ListModel +{ + public: + TypeListModel() + { } + + /** + * Used to get number of line in the list + */ + int getNumberOfElements() override A_WARN_UNUSED +#ifdef EATHENA_SUPPORT +#ifdef MANASERV_SUPPORT + { return 4; } +#else + { return 3; } +#endif +#else +#ifdef MANASERV_SUPPORT + { return 3; } +#else + { return 2; } +#endif +#endif + + /** + * Used to get an element from the list + */ + std::string getElementAt(int elementIndex) override A_WARN_UNUSED; +}; + +/** + * The custom server addition dialog. + * + * \ingroup Interface + */ +class EditServerDialog final : public Window, + public gcn::ActionListener, + public gcn::KeyListener +{ + public: + EditServerDialog(ServerDialog *const parent, ServerInfo server, + const int index); + + A_DELETE_COPY(EditServerDialog) + + ~EditServerDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + void keyPressed(gcn::KeyEvent &keyEvent) override; + + private: + TextField *mServerAddressField; + TextField *mPortField; + TextField *mNameField; + TextField *mDescriptionField; + TextField *mOnlineListUrlField; + Button *mConnectButton; + Button *mOkButton; + Button *mCancelButton; + + TypeListModel *mTypeListModel; + DropDown *mTypeField; + + ServerDialog *mServerDialog; + ServerInfo mServer; + int mIndex; +}; + +#endif // GUI_EDITSERVERDIALOG_H diff --git a/src/gui/windows/emotewindow.cpp b/src/gui/windows/emotewindow.cpp new file mode 100644 index 000000000..cdff2d31d --- /dev/null +++ b/src/gui/windows/emotewindow.cpp @@ -0,0 +1,229 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/emotewindow.h" + +#include "gui/widgets/colormodel.h" +#include "gui/widgets/colorpage.h" +#include "gui/widgets/emotepage.h" +#include "gui/widgets/namesmodel.h" +#include "gui/widgets/scrollarea.h" +#include "gui/widgets/tabbedarea.h" + +#include "utils/gettext.h" + +#include "resources/image.h" +#include "resources/imageset.h" + +#include "debug.h" + +static const int fontSizeListSize = 2; + +static const char *const fontSizeList[] = +{ + // TRANSLATORS: font size + N_("Normal font"), + // TRANSLATORS: font size + N_("Bold font"), +}; + +EmoteWindow::EmoteWindow() : + // TRANSLATORS: emotes window name + Window(_("Emotes"), false, nullptr, "emotes.xml"), + mTabs(new TabbedArea(this)), + mEmotePage(new EmotePage(this)), + mColorModel(ColorModel::createDefault(this)), + mColorPage(new ColorPage(this, mColorModel, "colorpage.xml")), + mScrollColorPage(new ScrollArea(mColorPage, false, "emotepage.xml")), + mFontModel(new NamesModel), + mFontPage(new ListBox(this, mFontModel, "")), + mScrollFontPage(new ScrollArea(mFontPage, false, "fontpage.xml")), + mImageSet(Theme::getImageSetFromThemeXml("emotetabs.xml", "", 17, 16)) +{ + setShowTitle(false); + setResizable(true); + + addMouseListener(this); + const int pad2 = mPadding * 2; + const int width = 200; + const int height = 150; + setWidth(width + pad2); + setHeight(height + pad2); + add(mTabs); + mTabs->setPosition(mPadding, mPadding); + mTabs->setWidth(width); + mTabs->setHeight(height); + center(); + + setTitleBarHeight(getPadding() + getTitlePadding()); + mScrollColorPage->setVerticalScrollPolicy(ScrollArea::SHOW_ALWAYS); + mScrollColorPage->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); + mScrollFontPage->setVerticalScrollPolicy(ScrollArea::SHOW_NEVER); + mScrollFontPage->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); + + mFontModel->fillFromArray(&fontSizeList[0], fontSizeListSize); + mFontPage->setCenter(true); + + if (mImageSet && mImageSet->size() >= 3) + { + for (int f = 0; f < 3; f ++) + { + Image *const image = mImageSet->get(f); + if (image) + image->incRef(); + } + + mTabs->addTab(mImageSet->get(0), mEmotePage); + mTabs->addTab(mImageSet->get(2), mScrollColorPage); + mTabs->addTab(mImageSet->get(1), mScrollFontPage); + } + else + { + // TRANSLATORS: emotes tab name + mTabs->addTab(_("Emotes"), mEmotePage); + // TRANSLATORS: emotes tab name + mTabs->addTab(_("Colors"), mScrollColorPage); + // TRANSLATORS: emotes tab name + mTabs->addTab(_("Fonts"), mScrollFontPage); + } + + mEmotePage->setActionEventId("emote"); + mColorPage->setActionEventId("color"); + mFontPage->setActionEventId("font"); +} + +EmoteWindow::~EmoteWindow() +{ + mTabs->removeAll(false); + mTabs->removeTab(mTabs->getTabByIndex(0)); + delete mEmotePage; + mEmotePage = nullptr; + delete mColorPage; + mColorPage = nullptr; + delete mColorModel; + mColorModel = nullptr; + delete mScrollColorPage; + mScrollColorPage = nullptr; + delete mFontPage; + mFontPage = nullptr; + delete mFontModel; + mFontModel = nullptr; + delete mScrollFontPage; + mScrollFontPage = nullptr; + if (mImageSet) + { + mImageSet->decRef(); + mImageSet = nullptr; + } +} + +void EmoteWindow::show() +{ + setVisible(true); +} + +void EmoteWindow::hide() +{ + setVisible(false); +} + +std::string EmoteWindow::getSelectedEmote() const +{ + const int index = mEmotePage->getSelectedIndex(); + if (index < 0) + return std::string(); + + char chr[2]; + chr[0] = '0' + index; + chr[1] = 0; + return std::string("%%").append(&chr[0]); +} + +void EmoteWindow::clearEmote() +{ + const int index = mEmotePage->getSelectedIndex(); + mEmotePage->resetAction(); + if (index >= 0) + setVisible(false); +} + +std::string EmoteWindow::getSelectedColor() const +{ + const int index = mColorPage->getSelected(); + if (index < 0) + return std::string(); + + char chr[2]; + chr[0] = '0' + index; + chr[1] = 0; + return std::string("##").append(&chr[0]); +} + +void EmoteWindow::clearColor() +{ + mColorPage->resetAction(); + setVisible(false); +} + +std::string EmoteWindow::getSelectedFont() const +{ + const int index = mFontPage->getSelected(); + if (index < 0) + return std::string(); + + if (!index) + return "##b"; + else + return "##B"; +} + +void EmoteWindow::clearFont() +{ + mFontPage->setSelected(-1); + setVisible(false); +} + +void EmoteWindow::addListeners(gcn::ActionListener *const listener) +{ + mEmotePage->addActionListener(listener); + mColorPage->addActionListener(listener); + mFontPage->addActionListener(listener); +} + +void EmoteWindow::widgetResized(const gcn::Event &event) +{ + Window::widgetResized(event); + const int pad2 = mPadding * 2; + const int width = mDimension.width; + const int height = mDimension.height; + + mTabs->setSize(width - pad2, height - pad2); + mTabs->adjustWidget(mEmotePage); + mTabs->adjustWidget(mScrollColorPage); + mColorPage->setSize(mScrollColorPage->getWidth(), + mScrollColorPage->getHeight()); + mEmotePage->widgetResized(event); +} + +void EmoteWindow::widgetMoved(const gcn::Event &event) +{ + Window::widgetMoved(event); + mEmotePage->widgetResized(event); +} diff --git a/src/gui/windows/emotewindow.h b/src/gui/windows/emotewindow.h new file mode 100644 index 000000000..b65c0c13c --- /dev/null +++ b/src/gui/windows/emotewindow.h @@ -0,0 +1,80 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_EMOTEWINDOW_H +#define GUI_EMOTEWINDOW_H + +#include "gui/widgets/window.h" + +class ColorModel; +class ColorPage; +class EmotePage; +class ImageSet; +class ListBox; +class NamesModel; +class ScrollArea; +class TabbedArea; + +class EmoteWindow final : public Window +{ + public: + EmoteWindow(); + + A_DELETE_COPY(EmoteWindow) + + ~EmoteWindow(); + + void show(); + + void hide(); + + std::string getSelectedEmote() const; + + void clearEmote(); + + std::string getSelectedColor() const; + + void clearColor(); + + std::string getSelectedFont() const; + + void clearFont(); + + void addListeners(gcn::ActionListener *const listener); + + void widgetResized(const gcn::Event &event) override; + + void widgetMoved(const gcn::Event &event) override; + + private: + TabbedArea *mTabs; + EmotePage *mEmotePage; + ColorModel *mColorModel; + ColorPage *mColorPage; + ScrollArea *mScrollColorPage; + NamesModel *mFontModel; + ListBox *mFontPage; + ScrollArea *mScrollFontPage; + ImageSet *mImageSet; +}; + +extern EmoteWindow *emoteWindow; + +#endif // GUI_EMOTEWINDOW_H diff --git a/src/gui/windows/equipmentwindow.cpp b/src/gui/windows/equipmentwindow.cpp new file mode 100644 index 000000000..0402115df --- /dev/null +++ b/src/gui/windows/equipmentwindow.cpp @@ -0,0 +1,669 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/equipmentwindow.h" + +#include "configuration.h" +#include "dragdrop.h" +#include "graphicsvertexes.h" +#include "inventory.h" +#include "item.h" + +#include "being/being.h" +#include "being/localplayer.h" +#include "being/playerinfo.h" + +#include "gui/itempopup.h" +#include "gui/viewport.h" + +#include "gui/windows/setup.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/playerbox.h" + +#include "net/inventoryhandler.h" +#include "net/net.h" + +#include "resources/imageset.h" + +#include "utils/dtor.h" +#include "utils/gettext.h" + +#include + +#include + +#include "debug.h" + +static const int BOX_COUNT = 13; + +EquipmentWindow::EquipmentWindow(Equipment *const equipment, + Being *const being, + const bool foring): + // TRANSLATORS: equipment window name + Window(_("Equipment"), false, nullptr, "equipment.xml"), + gcn::ActionListener(), + mEquipment(equipment), + mItemPopup(new ItemPopup), + mPlayerBox(new PlayerBox("equipment_playerbox.xml", + "equipment_selectedplayerbox.xml")), + // TRANSLATORS: equipment window button + mUnequip(new Button(this, _("Unequip"), "unequip", this)), + mSelected(-1), + mForing(foring), + mImageSet(nullptr), + mBeing(being), + mBoxes(), + mHighlightColor(getThemeColor(Theme::HIGHLIGHT)), + mBorderColor(getThemeColor(Theme::BORDER)), + mLabelsColor(getThemeColor(Theme::LABEL)), + mLabelsColor2(getThemeColor(Theme::LABEL_OUTLINE)), + mSlotBackground(), + mSlotHighlightedBackground(), + mVertexes(new ImageCollection), + mItemPadding(getOption("itemPadding")), + mBoxSize(getOption("boxSize")), + mButtonPadding(getOption("buttonPadding", 5)), + mMinX(180), + mMinY(345), + mMaxX(0), + mMaxY(0) +{ + if (setupWindow) + setupWindow->registerWindowForReset(this); + + if (!mBoxSize) + mBoxSize = 36; + + // Control that shows the Player + mPlayerBox->setDimension(gcn::Rectangle(50, 80, 74, 168)); + mPlayerBox->setPlayer(being); + + if (foring) + setWindowName("Being equipment"); + else + setWindowName("Equipment"); + + setCloseButton(true); + setSaveVisible(true); + setStickyButtonLock(true); + + mBoxes.reserve(BOX_COUNT); + for (int f = 0; f < BOX_COUNT; f ++) + mBoxes.push_back(nullptr); + + fillBoxes(); + recalcSize(); + + loadWindowState(); + + const gcn::Rectangle &area = getChildrenArea(); + mUnequip->setPosition(area.width - mUnequip->getWidth() - mButtonPadding, + area.height - mUnequip->getHeight() - mButtonPadding); + mUnequip->setEnabled(false); + + ImageRect rect; + Theme::instance()->loadRect(rect, "equipment_background.xml", "", 0, 1); + mSlotBackground = rect.grid[0]; + mSlotHighlightedBackground = rect.grid[1]; + add(mPlayerBox); + add(mUnequip); + enableVisibleSound(true); +} + +EquipmentWindow::~EquipmentWindow() +{ + delete mItemPopup; + mItemPopup = nullptr; + if (this == beingEquipmentWindow) + { + if (mEquipment) + delete mEquipment->getBackend(); + delete mEquipment; + mEquipment = nullptr; + } + delete_all(mBoxes); + mBoxes.clear(); + if (mImageSet) + { + mImageSet->decRef(); + mImageSet = nullptr; + } + if (mSlotBackground) + mSlotBackground->decRef(); + if (mSlotHighlightedBackground) + mSlotHighlightedBackground->decRef(); + delete mVertexes; + mVertexes = nullptr; +} + +void EquipmentWindow::draw(gcn::Graphics *graphics) +{ + BLOCK_START("EquipmentWindow::draw") + // Draw window graphics + Window::draw(graphics); + Graphics *const g = static_cast(graphics); + + int i = 0; + gcn::Font *const font = getFont(); + const int fontHeight = font->getHeight(); + + if (openGLMode != RENDER_SAFE_OPENGL) + { + if (mLastRedraw) + { + mVertexes->clear(); + FOR_EACH (std::vector::const_iterator, it, mBoxes) + { + const EquipmentBox *const box = *it; + if (!box) + continue; + if (i == mSelected) + { + g->calcTile(mVertexes, mSlotHighlightedBackground, + box->x, box->y); + } + else + { + g->calcTile(mVertexes, mSlotBackground, box->x, box->y); + } + } + } + g->drawTile(mVertexes); + } + else + { + for (std::vector::const_iterator it = mBoxes.begin(), + it_end = mBoxes.end(); it != it_end; ++ it, ++ i) + { + const EquipmentBox *const box = *it; + if (!box) + continue; + if (i == mSelected) + g->drawImage(mSlotHighlightedBackground, box->x, box->y); + else + g->drawImage(mSlotBackground, box->x, box->y); + } + } + + if (!mEquipment) + { + BLOCK_END("EquipmentWindow::draw") + return; + } + + i = 0; + for (std::vector::const_iterator it = mBoxes.begin(), + it_end = mBoxes.end(); it != it_end; ++ it, ++ i) + { + const EquipmentBox *const box = *it; + if (!box) + continue; + const Item *const item = mEquipment->getEquipment(i); + if (item) + { + // Draw Item. + Image *const image = item->getImage(); + if (image) + { + image->setAlpha(1.0F); // Ensure the image is drawn + // with maximum opacity + g->drawImage(image, box->x + mItemPadding, + box->y + mItemPadding); + if (i == EQUIP_PROJECTILE_SLOT) + { + g->setColorAll(mLabelsColor, mLabelsColor2); + const std::string str = toString(item->getQuantity()); + font->drawString(g, str, + box->x + (mBoxSize - font->getWidth(str)) / 2, + box->y - fontHeight); + } + } + } + else if (box->image) + { + g->drawImage(box->image, box->x + mItemPadding, + box->y + mItemPadding); + } + } + BLOCK_END("EquipmentWindow::draw") +} + +void EquipmentWindow::action(const gcn::ActionEvent &event) +{ + if (!mEquipment) + return; + + if (event.getId() == "unequip" && mSelected > -1) + { + const Item *const item = mEquipment->getEquipment(mSelected); + Net::getInventoryHandler()->unequipItem(item); + setSelected(-1); + } +} + +Item *EquipmentWindow::getItem(const int x, const int y) const +{ + if (!mEquipment) + return nullptr; + + int i = 0; + + for (std::vector::const_iterator it = mBoxes.begin(), + it_end = mBoxes.end(); it != it_end; ++ it, ++ i) + { + const EquipmentBox *const box = *it; + if (!box) + continue; + const gcn::Rectangle tRect(box->x, box->y, mBoxSize, mBoxSize); + + if (tRect.isPointInRect(x, y)) + return mEquipment->getEquipment(i); + } + return nullptr; +} + +void EquipmentWindow::mousePressed(gcn::MouseEvent& mouseEvent) +{ + if (!mEquipment) + { + Window::mousePressed(mouseEvent); + return; + } + + const int x = mouseEvent.getX(); + const int y = mouseEvent.getY(); + + if (mouseEvent.getButton() == gcn::MouseEvent::LEFT) + { + if (mForing) + { + Window::mousePressed(mouseEvent); + return; + } + // Checks if any of the presses were in the equip boxes. + int i = 0; + + bool inBox(false); + + for (std::vector::const_iterator it = mBoxes.begin(), + it_end = mBoxes.end(); it != it_end; ++ it, ++ i) + { + const EquipmentBox *const box = *it; + if (!box) + continue; + const Item *const item = mEquipment->getEquipment(i); + const gcn::Rectangle tRect(box->x, box->y, mBoxSize, mBoxSize); + + if (tRect.isPointInRect(x, y)) + { + inBox = true; + if (item) + { + setSelected(i); + dragDrop.dragItem(item, DRAGDROP_SOURCE_EQUIPMENT); + return; + } + } + if (inBox) + return; + } + } + else if (mouseEvent.getButton() == gcn::MouseEvent::RIGHT) + { + if (Item *const item = getItem(x, y)) + { + if (mItemPopup) + mItemPopup->setVisible(false); + + /* Convert relative to the window coordinates to absolute screen + * coordinates. + */ + const int mx = x + getX(); + const int my = y + getY(); + if (viewport) + { + if (mForing) + viewport->showUndressPopup(mx, my, mBeing, item); + else + viewport->showPopup(this, mx, my, item, true); + } + } + } + Window::mousePressed(mouseEvent); +} + +void EquipmentWindow::mouseReleased(gcn::MouseEvent &mouseEvent) +{ + Window::mouseReleased(mouseEvent); + const DragDropSource src = dragDrop.getSource(); + if (dragDrop.isEmpty() || (src != DRAGDROP_SOURCE_INVENTORY + && src != DRAGDROP_SOURCE_EQUIPMENT)) + { + return; + } + Inventory *const inventory = player_node + ? PlayerInfo::getInventory() : nullptr; + if (!inventory) + return; + + Item *const item = inventory->findItem(dragDrop.getItem(), + dragDrop.getItemColor()); + if (!item) + return; + + if (dragDrop.getSource() == DRAGDROP_SOURCE_INVENTORY) + { + if (item->isEquipment()) + { + if (!item->isEquipped()) + Net::getInventoryHandler()->equipItem(item); + } + } + else if (dragDrop.getSource() == DRAGDROP_SOURCE_EQUIPMENT) + { + if (item->isEquipment()) + { + const int x = mouseEvent.getX(); + const int y = mouseEvent.getY(); + int i = 0; + for (std::vector::const_iterator + it = mBoxes.begin(), it_end = mBoxes.end(); + it != it_end; ++ it, ++ i) + { + const EquipmentBox *const box = *it; + if (!box) + continue; + const gcn::Rectangle tRect(box->x, box->y, mBoxSize, mBoxSize); + + if (tRect.isPointInRect(x, y)) + return; + } + + if (item->isEquipped()) + Net::getInventoryHandler()->unequipItem(item); + } + } + dragDrop.clear(); + dragDrop.deselect(); +} + +// Show ItemTooltip +void EquipmentWindow::mouseMoved(gcn::MouseEvent &event) +{ + Window::mouseMoved(event); + + if (!mItemPopup) + return; + + const int x = event.getX(); + const int y = event.getY(); + + const Item *const item = getItem(x, y); + + if (item) + { + int mouseX, mouseY; + SDL_GetMouseState(&mouseX, &mouseY); + + mItemPopup->setItem(item); + mItemPopup->position(x + getX(), y + getY()); + } + else + { + mItemPopup->setVisible(false); + } +} + +// Hide ItemTooltip +void EquipmentWindow::mouseExited(gcn::MouseEvent &event A_UNUSED) +{ + if (mItemPopup) + mItemPopup->setVisible(false); +} + +void EquipmentWindow::setSelected(const int index) +{ + mSelected = index; + mRedraw = true; + if (mUnequip) + mUnequip->setEnabled(mSelected != -1); + if (mItemPopup) + mItemPopup->setVisible(false); +} + +void EquipmentWindow::setBeing(Being *const being) +{ + mPlayerBox->setPlayer(being); + mBeing = being; + if (mEquipment) + delete mEquipment->getBackend(); + delete mEquipment; + if (!being) + { + mEquipment = nullptr; + return; + } + mEquipment = being->getEquipment(); +} + +void EquipmentWindow::updateBeing(Being *const being) +{ + if (being == mBeing) + setBeing(being); +} + +void EquipmentWindow::resetBeing(const Being *const being) +{ + if (being == mBeing) + setBeing(nullptr); +} + +void EquipmentWindow::fillBoxes() +{ + XML::Document *const doc = new XML::Document( + paths.getStringValue("equipmentWindowFile")); + const XmlNodePtr root = doc->rootNode(); + if (!root) + { + delete doc; + fillDefault(); + return; + } + + if (mImageSet) + mImageSet->decRef(); + + mImageSet = Theme::getImageSetFromTheme(XML::getProperty( + root, "image", "equipmentbox.png"), 32, 32); + + for_each_xml_child_node(node, root) + { + if (xmlNameEqual(node, "playerbox")) + loadPlayerBox(node); + else if (xmlNameEqual(node, "slot")) + loadSlot(node, mImageSet); + } + delete doc; +} + +void EquipmentWindow::loadPlayerBox(const XmlNodePtr playerBoxNode) +{ + mPlayerBox->setDimension(gcn::Rectangle( + XML::getProperty(playerBoxNode, "x", 50), + XML::getProperty(playerBoxNode, "y", 80), + XML::getProperty(playerBoxNode, "width", 74), + XML::getProperty(playerBoxNode, "height", 168))); +} + +void EquipmentWindow::loadSlot(const XmlNodePtr slotNode, + const ImageSet *const imageset) +{ + const int slot = parseSlotName(XML::getProperty(slotNode, "name", "")); + if (slot < 0) + return; + + const int x = XML::getProperty(slotNode, "x", 0) + getPadding(); + const int y = XML::getProperty(slotNode, "y", 0) + getTitleBarHeight(); + const int imageIndex = XML::getProperty(slotNode, "image", -1); + Image *image = nullptr; + + if (imageset && imageIndex >= 0 && imageIndex + < static_cast(imageset->size())) + { + image = imageset->get(imageIndex); + } + + if (mBoxes[slot]) + { + EquipmentBox *const box = mBoxes[slot]; + box->x = x; + box->y = y; + box->image = image; + } + else + { + mBoxes[slot] = new EquipmentBox(x, y, image); + } + if (x < mMinX) + mMinX = x; + if (y < mMinY) + mMinY = y; + if (x + mBoxSize > mMaxX) + mMaxX = x + mBoxSize; + if (y + mBoxSize > mMaxY) + mMaxY = y + mBoxSize; +} + +int EquipmentWindow::parseSlotName(const std::string &name) const +{ + int id = -1; + if (name == "shoes" || name == "boot" || name == "boots") + { + id = 4; + } + else if (name == "bottomclothes" || name == "bottom" || name == "pants") + { + id = 3; + } + else if (name == "topclothes" || name == "top" + || name == "torso" || name == "body") + { + id = 0; + } + else if (name == "misc1" || name == "cape") + { + id = 5; + } + else if (name == "misc2" || name == "scarf" || name == "scarfs") + { + id = 7; + } + else if (name == "hat" || name == "hats") + { + id = 2; + } + else if (name == "wings") + { + id = 6; + } + else if (name == "glove" || name == "gloves") + { + id = 1; + } + else if (name == "weapon" || name == "weapons") + { + id = 8; + } + else if (name == "shield" || name == "shields") + { + id = 9; + } + else if (name == "amulet" || name == "amulets") + { + id = 11; + } + else if (name == "ring" || name == "rings") + { + id = 12; + } + else if (name == "arrow" || name == "arrows" || name == "ammo") + { + id = 10; + } + + return id; +} + +void EquipmentWindow::fillDefault() +{ + if (mImageSet) + mImageSet->decRef(); + + mImageSet = Theme::getImageSetFromTheme( + "equipmentbox.png", 32, 32); + + addBox(0, 90, 40, 0); // torso + addBox(1, 8, 78, 1); // gloves + addBox(2, 70, 0, 2); // hat + addBox(3, 50, 253, 3); // pants + addBox(4, 90, 253, 4); // boots + addBox(5, 8, 213, 5); // FREE + addBox(6, 129, 213, 6); // wings + addBox(7, 50, 40, 5); // scarf + addBox(8, 8, 168, 7); // weapon + addBox(9, 129, 168, 8); // shield + addBox(10, 129, 78, 9); // ammo + addBox(11, 8, 123, 5); // amulet + addBox(12, 129, 123, 5); // ring +} + +void EquipmentWindow::addBox(const int idx, int x, int y, const int imageIndex) +{ + Image *image = nullptr; + + if (mImageSet && imageIndex >= 0 && imageIndex + < static_cast(mImageSet->size())) + { + image = mImageSet->get(imageIndex); + } + + x += getPadding(); + y += getTitleBarHeight(); + mBoxes[idx] = new EquipmentBox(x, y, image); + + if (x < mMinX) + mMinX = x; + if (y < mMinY) + mMinY = y; + if (x + mBoxSize > mMaxX) + mMaxX = x + mBoxSize; + if (y + mBoxSize > mMaxY) + mMaxY = y + mBoxSize; +} + +void EquipmentWindow::recalcSize() +{ + mMaxX += mMinX; + mMaxY += mMinY + mUnequip->getHeight() + mButtonPadding; + setDefaultSize(mMaxX, mMaxY, ImageRect::CENTER); +} diff --git a/src/gui/windows/equipmentwindow.h b/src/gui/windows/equipmentwindow.h new file mode 100644 index 000000000..5fd69c23a --- /dev/null +++ b/src/gui/windows/equipmentwindow.h @@ -0,0 +1,155 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_EQUIPMENTWINDOW_H +#define GUI_EQUIPMENTWINDOW_H + +#include "equipment.h" +#include "localconsts.h" + +#include "gui/widgets/window.h" + +#include "utils/xml.h" + +#include + +#include + +class Being; +class Button; +class Image; +class ImageSet; +class Item; +class ItemPopup; +class PlayerBox; + +struct EquipmentBox final +{ + EquipmentBox(const int x0, const int y0, Image *const img) : + x(x0), y(y0), image(img) + { } + + A_DELETE_COPY(EquipmentBox) + + int x; + int y; + Image *image; +}; + +/** + * Equipment dialog. + * + * \ingroup Interface + */ +class EquipmentWindow final : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor. + */ + EquipmentWindow(Equipment *const equipment, Being *const being, + const bool foring = false); + + A_DELETE_COPY(EquipmentWindow) + + /** + * Destructor. + */ + ~EquipmentWindow(); + + /** + * Draws the equipment window. + */ + void draw(gcn::Graphics *graphics) override; + + void action(const gcn::ActionEvent &event) override; + + void mousePressed(gcn::MouseEvent& mouseEvent) override; + + const Item* getEquipment(const int i) const A_WARN_UNUSED + { return mEquipment ? mEquipment->getEquipment(i) : nullptr; } + + void setBeing(Being *const being); + + void updateBeing(Being *const being); + + void resetBeing(const Being *const being); + + void mouseExited(gcn::MouseEvent &event) override; + + void mouseMoved(gcn::MouseEvent &event) override; + + void mouseReleased(gcn::MouseEvent &event) override; + + void recalcSize(); + + private: + Item *getItem(const int x, const int y) const A_WARN_UNUSED; + + void setSelected(const int index); + + void fillBoxes(); + + void fillDefault(); + + void addBox(const int idx, int x, int y, const int imageIndex); + + void loadWindow(const XmlNodePtr windowNode); + + void loadPlayerBox(const XmlNodePtr playerBoxNode); + + void loadSlot(const XmlNodePtr slotNode, + const ImageSet *const imageset); + + int parseSlotName(const std::string &name) const A_WARN_UNUSED; + + Equipment *mEquipment; + + ItemPopup *mItemPopup; + PlayerBox *mPlayerBox; + Button *mUnequip; + + int mSelected; /**< Index of selected item. */ + bool mForing; + ImageSet *mImageSet; + Being *mBeing; + std::vector mBoxes; + gcn::Color mHighlightColor; + gcn::Color mBorderColor; + gcn::Color mLabelsColor; + gcn::Color mLabelsColor2; + Image *mSlotBackground; + Image *mSlotHighlightedBackground; + ImageCollection *mVertexes; + int mItemPadding; + int mBoxSize; + int mButtonPadding; + int mMinX; + int mMinY; + int mMaxX; + int mMaxY; +}; + +extern EquipmentWindow *equipmentWindow; +extern EquipmentWindow *beingEquipmentWindow; + +#endif // GUI_EQUIPMENTWINDOW_H diff --git a/src/gui/windows/helpwindow.cpp b/src/gui/windows/helpwindow.cpp new file mode 100644 index 000000000..db85ea0bd --- /dev/null +++ b/src/gui/windows/helpwindow.cpp @@ -0,0 +1,196 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/helpwindow.h" + +#include "configuration.h" + +#include "gui/gui.h" +#include "gui/sdlfont.h" + +#include "gui/windows/didyouknowwindow.h" +#include "gui/windows/setup.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/browserbox.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/scrollarea.h" + +#include "resources/resourcemanager.h" + +#include "utils/gettext.h" +#include "utils/paths.h" +#include "utils/process.h" + +#include "utils/translation/podict.h" +#include "utils/translation/translationmanager.h" + +#include "debug.h" + +HelpWindow::HelpWindow() : + // TRANSLATORS: help window name + Window(_("Help"), false, nullptr, "help.xml"), + gcn::ActionListener(), + // TRANSLATORS: help window. button. + mDYKButton(new Button(this, _("Did you know..."), "DYK", this)), + mBrowserBox(new BrowserBox(this)), + mScrollArea(new ScrollArea(mBrowserBox, true, "help_background.xml")), + mTagFileMap() +{ + setMinWidth(300); + setMinHeight(220); + setContentSize(455, 350); + setWindowName("Help"); + setCloseButton(true); + setResizable(true); + setStickyButtonLock(true); + + if (setupWindow) + setupWindow->registerWindowForReset(this); + + setDefaultSize(500, 400, ImageRect::CENTER); + + mBrowserBox->setOpaque(false); + + mBrowserBox->setLinkHandler(this); + mBrowserBox->setFont(gui->getHelpFont()); + mBrowserBox->setProcessVersion(true); + mBrowserBox->setEnableImages(true); + mBrowserBox->setEnableKeys(true); + mBrowserBox->setEnableTabs(true); + + place(4, 3, mDYKButton); + place(0, 0, mScrollArea, 5, 3).setPadding(3); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + + loadWindowState(); + loadTags(); + enableVisibleSound(true); +} + +void HelpWindow::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "DYK") + { + if (didYouKnowWindow) + { + didYouKnowWindow->setVisible(!didYouKnowWindow->isWindowVisible()); + if (didYouKnowWindow->isWindowVisible()) + didYouKnowWindow->requestMoveToTop(); + } + } +} + +void HelpWindow::handleLink(const std::string &link, + gcn::MouseEvent *event A_UNUSED) +{ + if (!strStartWith(link, "http://") && !strStartWith(link, "https://")) + { + std::string helpFile = link; + loadHelp(helpFile); + } + else + { + openBrowser(link); + } +} + +void HelpWindow::loadHelp(const std::string &helpFile) +{ + if (!checkPath(helpFile)) + return; + mBrowserBox->clearRows(); + loadFile("header"); + loadFile(helpFile); + loadFile("footer"); + mScrollArea->setVerticalScrollAmount(0); + setVisible(true); +} + +void HelpWindow::loadFile(std::string file) +{ + trim(file); + std::string helpPath = branding.getStringValue("helpPath"); + if (helpPath.empty()) + helpPath = paths.getStringValue("help"); + + StringVect lines; + TranslationManager::translateFile(helpPath.append(file).append(".txt"), + translator, lines); + + for (size_t i = 0, sz = lines.size(); i < sz; ++i) + mBrowserBox->addRow(lines[i]); +} + +void HelpWindow::loadTags() +{ + std::string helpPath = branding.getStringValue("helpPath"); + if (helpPath.empty()) + helpPath = paths.getStringValue("help"); + StringVect lines; + ResourceManager::loadTextFile(helpPath.append("tags.idx"), lines); + FOR_EACH (StringVectCIter, it, lines) + { + const std::string &str = *it; + const size_t idx = str.find('|'); + if (idx != std::string::npos) + mTagFileMap[str.substr(idx + 1)].insert(str.substr(0, idx)); + } +} + +void HelpWindow::search(const std::string &text0) +{ + std::string text = text0; + trim(text); + toLower(text); + if (mTagFileMap.find(text) == mTagFileMap.end()) + { + loadHelp("searchnotfound"); + } + else + { + const HelpNames &names = mTagFileMap[text]; + if (names.size() == 1) + { + loadHelp(*names.begin()); + } + else + { + if (!translator) + return; + mBrowserBox->clearRows(); + loadFile("header"); + loadFile("searchmany"); + FOR_EACH (HelpNamesCIter, it, names) + { + const char *const str = (*it).c_str(); + mBrowserBox->addRow(strprintf(" -> @@%s|%s@@", str, + translator->getChar(str))); + } + loadFile("footer"); + mScrollArea->setVerticalScrollAmount(0); + setVisible(true); + } + } +} diff --git a/src/gui/windows/helpwindow.h b/src/gui/windows/helpwindow.h new file mode 100644 index 000000000..1419e0a10 --- /dev/null +++ b/src/gui/windows/helpwindow.h @@ -0,0 +1,93 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_HELPWINDOW_H +#define GUI_HELPWINDOW_H + +#include "gui/widgets/linkhandler.h" +#include "gui/widgets/window.h" + +#include + +#include "localconsts.h" + +#include +#include + +class Button; +class BrowserBox; +class ScrollArea; + +typedef std::set HelpNames; +typedef HelpNames::const_iterator HelpNamesCIter; +typedef std::map HelpTagsMap; + +/** + * The help window. + */ +class HelpWindow final : public Window, public LinkHandler, + public gcn::ActionListener +{ + public: + /** + * Constructor. + */ + HelpWindow(); + + A_DELETE_COPY(HelpWindow) + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + /** + * Handles link action. + */ + void handleLink(const std::string &link, + gcn::MouseEvent *event A_UNUSED) override; + + /** + * Loads help in the dialog. + */ + void loadHelp(const std::string &helpFile); + + /** + * Seach for given text in tags. + */ + void search(const std::string &text); + + private: + void loadTags(); + + void loadFile(std::string file); + + Button *mDYKButton; + + BrowserBox *mBrowserBox; + ScrollArea *mScrollArea; + HelpTagsMap mTagFileMap; +}; + +extern HelpWindow *helpWindow; + +#endif // GUI_HELPWINDOW_H diff --git a/src/gui/windows/inventorywindow.cpp b/src/gui/windows/inventorywindow.cpp new file mode 100644 index 000000000..b57a7ea21 --- /dev/null +++ b/src/gui/windows/inventorywindow.cpp @@ -0,0 +1,835 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/inventorywindow.h" + +#include "configuration.h" +#include "item.h" +#include "units.h" + +#include "being/playerinfo.h" + +#include "input/inputmanager.h" +#include "input/keyevent.h" + +#include "gui/gui.h" +#include "gui/textpopup.h" +#include "gui/viewport.h" + +#include "gui/windows/equipmentwindow.h" +#include "gui/windows/itemamountwindow.h" +#include "gui/windows/outfitwindow.h" +#include "gui/windows/setup.h" +#include "gui/windows/shopwindow.h" +#include "gui/windows/tradewindow.h" + + +#include "gui/widgets/button.h" +#include "gui/widgets/dropdown.h" +#include "gui/widgets/itemcontainer.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/progressbar.h" +#include "gui/widgets/scrollarea.h" +#include "gui/widgets/tabstrip.h" +#include "gui/widgets/textfield.h" + +#include "net/inventoryhandler.h" +#include "net/net.h" + +#include "resources/itemdb.h" + +#include "utils/gettext.h" + +#include + +#include + +#include "debug.h" + +static const char *const SORT_NAME_INVENTORY[6] = +{ + // TRANSLATORS: inventory sort mode + N_("default"), + // TRANSLATORS: inventory sort mode + N_("by name"), + // TRANSLATORS: inventory sort mode + N_("by id"), + // TRANSLATORS: inventory sort mode + N_("by weight"), + // TRANSLATORS: inventory sort mode + N_("by amount"), + // TRANSLATORS: inventory sort mode + N_("by type") +}; + +class SortListModelInv final : public gcn::ListModel +{ +public: + ~SortListModelInv() + { } + + int getNumberOfElements() override + { return 6; } + + std::string getElementAt(int i) override + { + if (i >= getNumberOfElements() || i < 0) + return "???"; + + return gettext(SORT_NAME_INVENTORY[i]); + } +}; + +InventoryWindow::WindowList InventoryWindow::invInstances; + +InventoryWindow::InventoryWindow(Inventory *const inventory): + Window("Inventory", false, nullptr, "inventory.xml"), + gcn::ActionListener(), + gcn::KeyListener(), + gcn::SelectionListener(), + InventoryListener(), + mInventory(inventory), + mItems(new ItemContainer(this, mInventory)), + mWeight(), + mSlots(), + mUseButton(nullptr), + mDropButton(nullptr), + mSplitButton(nullptr), + mOutfitButton(nullptr), + mShopButton(nullptr), + mEquipmentButton(nullptr), + mStoreButton(nullptr), + mRetrieveButton(nullptr), + mInvCloseButton(nullptr), + mWeightBar(nullptr), + mSlotsBar(new ProgressBar(this, 0.0F, 100, 0, Theme::PROG_INVY_SLOTS)), + mFilter(nullptr), + mSortModel(new SortListModelInv), + mSortDropDown(new DropDown(this, mSortModel, false, false, this, "sort")), + mNameFilter(new TextField(this, "", true, this, "namefilter", true)), + mSortDropDownCell(nullptr), + mNameFilterCell(nullptr), + mFilterCell(nullptr), + mSlotsBarCell(nullptr), + mTextPopup(new TextPopup), + mSplit(false), + mCompactMode(false) +{ + if (inventory) + { + setCaption(gettext(inventory->getName().c_str())); + setWindowName(inventory->getName()); + } + else + { + // TRANSLATORS: inventory window name + setCaption(_("Inventory")); + setWindowName("Inventory"); + } + + listen(CHANNEL_ATTRIBUTES); + + if (setupWindow) + setupWindow->registerWindowForReset(this); + + setResizable(true); + setCloseButton(true); + setSaveVisible(true); + setStickyButtonLock(true); + + if (mainGraphics->mWidth > 600) + setDefaultSize(450, 310, ImageRect::CENTER); + else + setDefaultSize(387, 307, ImageRect::CENTER); + setMinWidth(310); + setMinHeight(179); + addKeyListener(this); + + mItems->addSelectionListener(this); + + gcn::ScrollArea *const invenScroll = new ScrollArea( + mItems, getOptionBool("showbackground"), "inventory_background.xml"); + invenScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + + const int size = config.getIntValue("fontSize"); + mFilter = new TabStrip(this, "filter_" + getWindowName(), size + 16); + mFilter->addActionListener(this); + mFilter->setActionEventId("tag_"); + + mSortDropDown->setSelected(0); + + StringVect tags = ItemDB::getTags(); + const size_t sz = tags.size(); + for (size_t f = 0; f < sz; f ++) + mFilter->addButton(tags[f]); + + if (isMainInventory()) + { + // TRANSLATORS: inventory button + const std::string equip = _("Equip"); + // TRANSLATORS: inventory button + const std::string use = _("Use"); + // TRANSLATORS: inventory button + const std::string unequip = _("Unequip"); + + std::string longestUseString = getFont()->getWidth(equip) > + getFont()->getWidth(use) ? equip : use; + + if (getFont()->getWidth(longestUseString) < + getFont()->getWidth(unequip)) + { + longestUseString = unequip; + } + + mUseButton = new Button(this, longestUseString, "use", this); + // TRANSLATORS: inventory button + mDropButton = new Button(this, _("Drop..."), "drop", this); + // TRANSLATORS: inventory button + mSplitButton = new Button(this, _("Split"), "split", this); + // TRANSLATORS: inventory button + mOutfitButton = new Button(this, _("Outfits"), "outfit", this); + // TRANSLATORS: inventory button + mShopButton = new Button(this, _("Shop"), "shop", this); + // TRANSLATORS: inventory button + mEquipmentButton = new Button(this, _("Equipment"), "equipment", this); + mWeightBar = new ProgressBar(this, 0.0F, 100, 0, Theme::PROG_WEIGHT); + + place(0, 0, mWeightBar, 4); + mSlotsBarCell = &place(4, 0, mSlotsBar, 5); + mSortDropDownCell = &place(9, 0, mSortDropDown, 2); + + mFilterCell = &place(0, 1, mFilter, 10).setPadding(3); + mNameFilterCell = &place(9, 1, mNameFilter, 2); + + place(0, 2, invenScroll, 11).setPadding(3); + place(0, 3, mUseButton); + place(1, 3, mDropButton); + place(8, 2, mSplitButton); + place(8, 3, mShopButton); + place(9, 3, mOutfitButton); + place(10, 3, mEquipmentButton); + + updateWeight(); + } + else + { + // TRANSLATORS: storage button + mStoreButton = new Button(this, _("Store"), "store", this); + // TRANSLATORS: storage button + mRetrieveButton = new Button(this, _("Retrieve"), "retrieve", this); + // TRANSLATORS: storage button + mInvCloseButton = new Button(this, _("Close"), "close", this); + + mSlotsBarCell = &place(0, 0, mSlotsBar, 6); + mSortDropDownCell = &place(6, 0, mSortDropDown, 1); + + mFilterCell = &place(0, 1, mFilter, 7).setPadding(3); + mNameFilterCell = &place(6, 1, mNameFilter, 1); + + place(0, 2, invenScroll, 7, 4); + place(0, 6, mStoreButton); + place(1, 6, mRetrieveButton); + place(6, 6, mInvCloseButton); + } + + Layout &layout = getLayout(); + layout.setRowHeight(2, Layout::AUTO_SET); + + mInventory->addInventoyListener(this); + + invInstances.push_back(this); + + if (inventory && inventory->isMainInventory()) + { + updateDropButton(); + } + else + { + if (!invInstances.empty()) + invInstances.front()->updateDropButton(); + } + + loadWindowState(); + enableVisibleSound(true); + slotsChanged(mInventory); + + widgetResized(gcn::Event(nullptr)); + if (!isMainInventory()) + setVisible(true); +} + +InventoryWindow::~InventoryWindow() +{ + invInstances.remove(this); + mInventory->removeInventoyListener(this); + if (!invInstances.empty()) + invInstances.front()->updateDropButton(); + + mSortDropDown->hideDrop(false); + delete mSortModel; + mSortModel = nullptr; + mTextPopup = nullptr; +} + +void InventoryWindow::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "outfit") + { + if (outfitWindow) + { + outfitWindow->setVisible(!outfitWindow->isWindowVisible()); + if (outfitWindow->isWindowVisible()) + outfitWindow->requestMoveToTop(); + } + } + else if (eventId == "shop") + { + if (shopWindow) + { + shopWindow->setVisible(!shopWindow->isWindowVisible()); + if (shopWindow->isWindowVisible()) + shopWindow->requestMoveToTop(); + } + } + else if (eventId == "equipment") + { + if (equipmentWindow) + { + equipmentWindow->setVisible(!equipmentWindow->isWindowVisible()); + if (equipmentWindow->isWindowVisible()) + equipmentWindow->requestMoveToTop(); + } + } + else if (eventId == "close") + { + close(); + } + else if (eventId == "store") + { + if (!inventoryWindow || !inventoryWindow->isWindowVisible()) + return; + + Item *const item = inventoryWindow->getSelectedItem(); + + if (!item) + return; + + ItemAmountWindow::showWindow(ItemAmountWindow::StoreAdd, this, item); + } + else if (eventId == "sort") + { + mItems->setSortType(mSortDropDown->getSelected()); + return; + } + else if (eventId == "namefilter") + { + mItems->setName(mNameFilter->getText()); + mItems->updateMatrix(); + } + else if (!eventId.find("tag_")) + { + std::string tagName = event.getId().substr(4); + mItems->setFilter(ItemDB::getTagId(tagName)); + return; + } + + Item *const item = mItems->getSelectedItem(); + + if (!item) + return; + + if (eventId == "use") + { + if (item->isEquipment()) + { + if (item->isEquipped()) + Net::getInventoryHandler()->unequipItem(item); + else + Net::getInventoryHandler()->equipItem(item); + } + else + { + if (PlayerInfo::isItemProtected(item->getId())) + return; + Net::getInventoryHandler()->useItem(item); + } + } + if (eventId == "equip") + { + if (!item->isEquipment()) + { + if (item->isEquipped()) + Net::getInventoryHandler()->unequipItem(item); + else + Net::getInventoryHandler()->equipItem(item); + } + else + { + if (PlayerInfo::isItemProtected(item->getId())) + return; + Net::getInventoryHandler()->useItem(item); + } + } + else if (eventId == "drop") + { + if (PlayerInfo::isItemProtected(item->getId())) + return; + + if (isStorageActive()) + { + Net::getInventoryHandler()->moveItem2(Inventory::INVENTORY, + item->getInvIndex(), item->getQuantity(), + Inventory::STORAGE); + } + else + { + if (inputManager.isActionActive(static_cast(Input::KEY_MOD))) + { + Net::getInventoryHandler()->dropItem( + item, item->getQuantity()); + } + else + { + ItemAmountWindow::showWindow(ItemAmountWindow::ItemDrop, + this, item); + } + } + } + else if (eventId == "split") + { + ItemAmountWindow::showWindow(ItemAmountWindow::ItemSplit, this, item, + (item->getQuantity() - 1)); + } + else if (eventId == "retrieve") + { + ItemAmountWindow::showWindow(ItemAmountWindow::StoreRemove, + this, item); + } +} + +Item *InventoryWindow::getSelectedItem() const +{ + return mItems->getSelectedItem(); +} + +void InventoryWindow::unselectItem() +{ + mItems->selectNone(); +} + +void InventoryWindow::widgetHidden(const gcn::Event &event) +{ + Window::widgetHidden(event); + mItems->hidePopup(); +} + +void InventoryWindow::mouseClicked(gcn::MouseEvent &event) +{ + Window::mouseClicked(event); + + const int clicks = event.getClickCount(); + + if (clicks == 2 && gui) + gui->resetClickCount(); + + const bool mod = (isStorageActive() && inputManager.isActionActive( + static_cast(Input::KEY_MOD))); + + const bool mod2 = (tradeWindow && tradeWindow->isWindowVisible() + && inputManager.isActionActive(static_cast(Input::KEY_MOD))); + + if (!mod && !mod2 && event.getButton() == gcn::MouseEvent::RIGHT) + { + Item *const item = mItems->getSelectedItem(); + + if (!item) + return; + + /* Convert relative to the window coordinates to absolute screen + * coordinates. + */ + const int mx = event.getX() + getX(); + const int my = event.getY() + getY(); + + if (viewport) + viewport->showPopup(this, mx, my, item, isMainInventory()); + } + + if (!mInventory) + return; + + if (event.getButton() == gcn::MouseEvent::LEFT + || event.getButton() == gcn::MouseEvent::RIGHT) + { + Item *const item = mItems->getSelectedItem(); + + if (!item) + return; + + if (mod) + { + if (mInventory->isMainInventory()) + { + if (event.getButton() == gcn::MouseEvent::RIGHT) + { + ItemAmountWindow::showWindow(ItemAmountWindow::StoreAdd, + inventoryWindow, item); + } + else + { + Net::getInventoryHandler()->moveItem2(Inventory::INVENTORY, + item->getInvIndex(), item->getQuantity(), + Inventory::STORAGE); + } + } + else + { + if (event.getButton() == gcn::MouseEvent::RIGHT) + { + ItemAmountWindow::showWindow(ItemAmountWindow::StoreRemove, + inventoryWindow, item); + } + else + { + Net::getInventoryHandler()->moveItem2(Inventory::STORAGE, + item->getInvIndex(), item->getQuantity(), + Inventory::INVENTORY); + } + } + } + else if (mod2 && mInventory->isMainInventory()) + { + if (PlayerInfo::isItemProtected(item->getId())) + return; + if (event.getButton() == gcn::MouseEvent::RIGHT) + { + ItemAmountWindow::showWindow(ItemAmountWindow::TradeAdd, + tradeWindow, item); + } + else + { + if (tradeWindow) + tradeWindow->tradeItem(item, item->getQuantity(), true); + } + } + else if (clicks == 2) + { + if (mInventory->isMainInventory()) + { + if (isStorageActive()) + { + ItemAmountWindow::showWindow(ItemAmountWindow::StoreAdd, + inventoryWindow, item); + } + else if (tradeWindow && tradeWindow->isWindowVisible()) + { + if (PlayerInfo::isItemProtected(item->getId())) + return; + ItemAmountWindow::showWindow(ItemAmountWindow::TradeAdd, + tradeWindow, item); + } + else + { + if (item->isEquipment()) + { + if (item->isEquipped()) + Net::getInventoryHandler()->unequipItem(item); + else + Net::getInventoryHandler()->equipItem(item); + } + else + { + if (PlayerInfo::isItemProtected(item->getId())) + return; + Net::getInventoryHandler()->useItem(item); + } + } + } + else + { + if (isStorageActive()) + { + ItemAmountWindow::showWindow(ItemAmountWindow::StoreRemove, + inventoryWindow, item); + } + } + } + } +} + +void InventoryWindow::mouseMoved(gcn::MouseEvent &event) +{ + Window::mouseMoved(event); + const gcn::Widget *const src = event.getSource(); + if (src == mSlotsBar || src == mWeightBar) + { + const int x = event.getX(); + const int y = event.getY(); + const gcn::Rectangle &rect = mDimension; + mTextPopup->show(rect.x + x, rect.y + y, strprintf(_("Money: %s"), + Units::formatCurrency(PlayerInfo::getAttribute( + PlayerInfo::MONEY)).c_str())); + } + else + { + mTextPopup->hide(); + } +} + +void InventoryWindow::mouseExited(gcn::MouseEvent &event A_UNUSED) +{ + mTextPopup->hide(); +} + +void InventoryWindow::keyPressed(gcn::KeyEvent &event) +{ + if (static_cast(&event)->getActionId() + == static_cast(Input::KEY_GUI_MOD)) + { + mSplit = true; + } +} + +void InventoryWindow::keyReleased(gcn::KeyEvent &event) +{ + if (static_cast(&event)->getActionId() + == static_cast(Input::KEY_GUI_MOD)) + { + mSplit = false; + } +} + +void InventoryWindow::valueChanged(const gcn::SelectionEvent &event A_UNUSED) +{ + if (!mInventory || !mInventory->isMainInventory()) + return; + + Item *const item = mItems->getSelectedItem(); + + if (mSplit && item && Net::getInventoryHandler()-> + canSplit(mItems->getSelectedItem())) + { + ItemAmountWindow::showWindow(ItemAmountWindow::ItemSplit, + this, item, item->getQuantity() - 1); + } + updateButtons(item); +} + +void InventoryWindow::updateButtons(const Item *item) +{ + if (!mInventory || !mInventory->isMainInventory()) + return; + + const Item *const selectedItem = mItems->getSelectedItem(); + if (item && selectedItem != item) + return; + + if (!item) + item = selectedItem; + + if (!item || item->getQuantity() == 0) + { + if (mUseButton) + mUseButton->setEnabled(true); + if (mDropButton) + mDropButton->setEnabled(true); + return; + } + + if (mUseButton) + mUseButton->setEnabled(true); + if (mDropButton) + mDropButton->setEnabled(true); + + if (mUseButton) + { + if (item->isEquipment()) + { + if (item->isEquipped()) + { + // TRANSLATORS: inventory button + mUseButton->setCaption(_("Unequip")); + } + else + { + // TRANSLATORS: inventory button + mUseButton->setCaption(_("Equip")); + } + } + else + { + // TRANSLATORS: inventory button + mUseButton->setCaption(_("Use")); + } + } + + updateDropButton(); + + if (mSplitButton) + { + if (Net::getInventoryHandler()->canSplit(item)) + mSplitButton->setEnabled(true); + else + mSplitButton->setEnabled(false); + } +} + +void InventoryWindow::setSplitAllowed(const bool allowed) +{ + mSplitButton->setVisible(allowed); +} + +void InventoryWindow::close() +{ + if (this == inventoryWindow) + { + setVisible(false); + } + else + { + if (Net::getInventoryHandler()) + Net::getInventoryHandler()->closeStorage(Inventory::STORAGE); + scheduleDelete(); + } +} + +void InventoryWindow::processEvent(const Channels channel A_UNUSED, + const DepricatedEvent &event) +{ + if (event.getName() == EVENT_UPDATEATTRIBUTE) + { + const int id = event.getInt("id"); + if (id == PlayerInfo::TOTAL_WEIGHT || id == PlayerInfo::MAX_WEIGHT) + updateWeight(); + } +} + +void InventoryWindow::updateWeight() +{ + if (!isMainInventory()) + return; + + const int total = PlayerInfo::getAttribute(PlayerInfo::TOTAL_WEIGHT); + const int max = PlayerInfo::getAttribute(PlayerInfo::MAX_WEIGHT); + + if (max <= 0) + return; + + // Adjust progress bar + mWeightBar->setProgress(static_cast(total) + / static_cast(max)); + mWeightBar->setText(strprintf("%s/%s", Units::formatWeight(total).c_str(), + Units::formatWeight(max).c_str())); +} + +void InventoryWindow::slotsChanged(Inventory *const inventory) +{ + if (inventory == mInventory) + { + const int usedSlots = mInventory->getNumberOfSlotsUsed(); + const int maxSlots = mInventory->getSize(); + + if (maxSlots) + { + mSlotsBar->setProgress(static_cast(usedSlots) + / static_cast(maxSlots)); + } + + mSlotsBar->setText(strprintf("%d/%d", usedSlots, maxSlots)); + mItems->updateMatrix(); + } +} + +void InventoryWindow::updateDropButton() +{ + if (!mDropButton) + return; + + if (isStorageActive()) + { + // TRANSLATORS: inventory button + mDropButton->setCaption(_("Store")); + } + else + { + const Item *const item = mItems->getSelectedItem(); + if (item && item->getQuantity() > 1) + { + // TRANSLATORS: inventory button + mDropButton->setCaption(_("Drop...")); + } + else + { + // TRANSLATORS: inventory button + mDropButton->setCaption(_("Drop")); + } + } +} + +bool InventoryWindow::isInputFocused() const +{ + return mNameFilter && mNameFilter->isFocused(); +} + +bool InventoryWindow::isAnyInputFocused() +{ + FOR_EACH (WindowList::const_iterator, it, invInstances) + { + if ((*it) && (*it)->isInputFocused()) + return true; + } + return false; +} + +void InventoryWindow::widgetResized(const gcn::Event &event) +{ + Window::widgetResized(event); + + if (!isMainInventory()) + return; + + if (getWidth() < 600) + { + if (!mCompactMode) + { + mNameFilter->setVisible(false); + mNameFilterCell->setType(LayoutCell::NONE); + mFilterCell->setWidth(mFilterCell->getWidth() + 2); + mCompactMode = true; + } + } + else if (mCompactMode) + { + mNameFilter->setVisible(true); + mNameFilterCell->setType(LayoutCell::WIDGET); + mFilterCell->setWidth(mFilterCell->getWidth() - 2); + mCompactMode = false; + } +} + +void InventoryWindow::setVisible(bool visible) +{ + if (!visible) + mSortDropDown->hideDrop(); + Window::setVisible(visible); +} diff --git a/src/gui/windows/inventorywindow.h b/src/gui/windows/inventorywindow.h new file mode 100644 index 000000000..7bd4ce466 --- /dev/null +++ b/src/gui/windows/inventorywindow.h @@ -0,0 +1,196 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_INVENTORYWINDOW_H +#define GUI_INVENTORYWINDOW_H + +#include "inventory.h" +#include "depricatedlistener.h" + +#include "gui/widgets/window.h" + +#include +#include +#include + +class Button; +class DropDown; +class Item; +class ItemContainer; +class Label; +class LayoutCell; +class ProgressBar; +class SortListModelInv; +class TabStrip; +class TextField; +class TextPopup; + +/** + * Inventory dialog. + * + * \ingroup Interface + */ +class InventoryWindow final : public Window, + public gcn::ActionListener, + public gcn::KeyListener, + public gcn::SelectionListener, + public InventoryListener, + public DepricatedListener +{ + public: + /** + * Constructor. + */ + explicit InventoryWindow(Inventory *const inventory); + + A_DELETE_COPY(InventoryWindow) + + /** + * Destructor. + */ + ~InventoryWindow(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + /** + * Returns the selected item. + */ + Item* getSelectedItem() const A_WARN_UNUSED; + + /** + * Unselect item + */ + void unselectItem(); + + /** + * Handles closing of the window + */ + void widgetHidden(const gcn::Event &event) override; + + /** + * Handles the mouse clicks. + */ + void mouseClicked(gcn::MouseEvent &event) override; + + /** + * Handles the key presses. + */ + void keyPressed(gcn::KeyEvent &event) override; + + /** + * Handles the key releases. + */ + void keyReleased(gcn::KeyEvent &event) override; + + /** + * Updates labels to currently selected item. + */ + void valueChanged(const gcn::SelectionEvent &event) override; + + /** + * Sets whether the split button should be shown. + */ + void setSplitAllowed(const bool allowed); + + /** + * Closes the Storage Window, as well as telling the server that the + * window has been closed. + */ + void close(); + + void slotsChanged(Inventory *const inventory); + + bool isMainInventory() const A_WARN_UNUSED + { return mInventory->isMainInventory(); } + + /** + * Returns true if any instances exist. + */ + static bool isStorageActive() A_WARN_UNUSED + { return invInstances.size() > 1; } + + void updateDropButton(); + + void processEvent(const Channels channel, + const DepricatedEvent &event) override; + + void updateButtons(const Item *item = nullptr); + + bool isInputFocused() const A_WARN_UNUSED; + + void widgetResized(const gcn::Event &event) override; + + void mouseMoved(gcn::MouseEvent &event) override; + + void mouseExited(gcn::MouseEvent &event) override; + + void setVisible(bool visible) override; + + static bool isAnyInputFocused(); + + private: + /** + * Updates the weight bar. + */ + void updateWeight(); + + typedef std::list WindowList; + static WindowList invInstances; + + Inventory *mInventory; + ItemContainer *mItems; + + std::string mWeight; + std::string mSlots; + + Button *mUseButton; + Button *mDropButton; + Button *mSplitButton; + Button *mOutfitButton; + Button *mShopButton; + Button *mEquipmentButton; + Button *mStoreButton; + Button *mRetrieveButton; + Button *mInvCloseButton; + + ProgressBar *mWeightBar; + ProgressBar *mSlotsBar; + TabStrip *mFilter; + SortListModelInv *mSortModel; + DropDown *mSortDropDown; + TextField *mNameFilter; + LayoutCell *mSortDropDownCell; + LayoutCell *mNameFilterCell; + LayoutCell *mFilterCell; + LayoutCell *mSlotsBarCell; + TextPopup *mTextPopup; + + bool mSplit; + bool mCompactMode; +}; + +extern InventoryWindow *inventoryWindow; + +#endif // GUI_INVENTORYWINDOW_H diff --git a/src/gui/windows/itemamountwindow.cpp b/src/gui/windows/itemamountwindow.cpp new file mode 100644 index 000000000..7c67fb976 --- /dev/null +++ b/src/gui/windows/itemamountwindow.cpp @@ -0,0 +1,451 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/itemamountwindow.h" + +#include "inventory.h" +#include "item.h" + +#include "input/keyboardconfig.h" + +#include "net/inventoryhandler.h" +#include "gui/itempopup.h" +#include "net/net.h" +#include "gui/viewport.h" + +#include "gui/windows/shopwindow.h" +#include "gui/windows/tradewindow.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/dropdown.h" +#include "gui/widgets/icon.h" +#include "gui/widgets/inttextfield.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/label.h" +#include "gui/widgets/slider.h" + +#include "utils/gettext.h" + +#include + +#include "debug.h" + +class ItemsModal final : public gcn::ListModel +{ +public: + ItemsModal() : + mStrings() + { + const std::map &items = ItemDB::getItemInfos(); + std::list tempStrings; + + for (std::map::const_iterator + i = items.begin(), i_end = items.end(); + i != i_end; ++i) + { + if (i->first < 0) + continue; + + const ItemInfo &info = *i->second; + const std::string name = info.getName(); + if (name != "unnamed" && !info.getName().empty() + && info.getName() != "unnamed") + { + tempStrings.push_back(name); + } + } + tempStrings.sort(); + FOR_EACH (std::list::const_iterator, i, tempStrings) + mStrings.push_back(*i); + } + + A_DELETE_COPY(ItemsModal) + + ~ItemsModal() + { } + + int getNumberOfElements() override + { + return static_cast(mStrings.size()); + } + + std::string getElementAt(int i) override + { + if (i < 0 || i >= getNumberOfElements()) + return "???"; + return mStrings.at(i); + } +private: + StringVect mStrings; +}; + +void ItemAmountWindow::finish(Item *const item, const int amount, + const int price, const Usage usage) +{ + switch (usage) + { + case TradeAdd: + if (tradeWindow) + tradeWindow->tradeItem(item, amount); + break; + case ItemDrop: + Net::getInventoryHandler()->dropItem(item, amount); + break; + case ItemSplit: + Net::getInventoryHandler()->splitItem(item, amount); + break; + case StoreAdd: + Net::getInventoryHandler()->moveItem2(Inventory::INVENTORY, + item->getInvIndex(), amount, Inventory::STORAGE); + break; + case StoreRemove: + Net::getInventoryHandler()->moveItem2(Inventory::STORAGE, + item->getInvIndex(), amount, Inventory::INVENTORY); + break; + case ShopBuyAdd: + if (shopWindow) + shopWindow->addBuyItem(item, amount, price); + break; + case ShopSellAdd: + if (shopWindow) + shopWindow->addSellItem(item, amount, price); + break; + default: + break; + } +} + +ItemAmountWindow::ItemAmountWindow(const Usage usage, Window *const parent, + Item *const item, const int maxRange) : + Window("", false, parent, "amount.xml"), + gcn::ActionListener(), + gcn::KeyListener(), + mItemAmountTextField(new IntTextField(this, 1)), + mItemPriceTextField(nullptr), + mGPLabel(nullptr), + mItem(item), + mItemIcon(new Icon(this, item ? item->getImage() : nullptr)), + mMax(maxRange), + mUsage(usage), + mItemPopup(new ItemPopup), + mItemAmountSlide(new Slider(1.0, mMax)), + mItemPriceSlide(nullptr), + mItemDropDown(nullptr), + mItemsModal(nullptr), + mPrice(0), + mEnabledKeyboard(keyboard.isEnabled()) +{ + if (!mItem) + { + setVisible(false); + return; + } + if (usage == ShopBuyAdd) + mMax = 10000; + else if (!mMax) + mMax = mItem->getQuantity(); + + keyboard.setEnabled(false); + + mItemAmountTextField->setRange(1, mMax); + mItemAmountTextField->setWidth(35); + mItemAmountTextField->addKeyListener(this); + + mItemAmountSlide->setHeight(10); + mItemAmountSlide->setActionEventId("slide"); + mItemAmountSlide->addActionListener(this); + + if (mUsage == ShopBuyAdd || mUsage == ShopSellAdd) + { + mItemPriceTextField = new IntTextField(this, 1); + mItemPriceTextField->setRange(1, 10000000); + mItemPriceTextField->setWidth(35); + mItemPriceTextField->addKeyListener(this); + + mItemPriceSlide = new Slider(1.0, 10000000); + mItemPriceSlide->setHeight(10); + mItemPriceSlide->setActionEventId("slidePrice"); + mItemPriceSlide->addActionListener(this); + + mGPLabel = new Label(this, " GP"); + } + + if (mUsage == ShopBuyAdd) + { + mItemsModal = new ItemsModal; + mItemDropDown = new DropDown(this, mItemsModal); + mItemDropDown->setActionEventId("itemType"); + mItemDropDown->addActionListener(this); + } + + // Buttons + // TRANSLATORS: item amount window button + Button *const minusAmountButton = new Button(this, _("-"), "dec", this); + // TRANSLATORS: item amount window button + Button *const plusAmountButton = new Button(this, _("+"), "inc", this); + // TRANSLATORS: item amount window button + Button *const okButton = new Button(this, _("OK"), "ok", this); + // TRANSLATORS: item amount window button + Button *const cancelButton = new Button(this, _("Cancel"), "cancel", this); + // TRANSLATORS: item amount window button + Button *const addAllButton = new Button(this, _("All"), "all", this); + + minusAmountButton->adjustSize(); + minusAmountButton->setWidth(plusAmountButton->getWidth()); + + // Set positions + ContainerPlacer placer; + placer = getPlacer(0, 0); + int n = 0; + if (mUsage == ShopBuyAdd) + { + placer(0, n, mItemDropDown, 8); + n++; + } + placer(1, n, minusAmountButton); + placer(2, n, mItemAmountTextField, 3); + placer(5, n, plusAmountButton); + placer(6, n, addAllButton); + + placer(0, n, mItemIcon, 1, 3); + placer(1, n + 1, mItemAmountSlide, 7); + + if (mUsage == ShopBuyAdd || mUsage == ShopSellAdd) + { + Button *const minusPriceButton = new Button( + // TRANSLATORS: item amount window button + this, _("-"), "decPrice", this); + Button *const plusPriceButton = new Button( + // TRANSLATORS: item amount window button + this, _("+"), "incPrice", this); + minusPriceButton->adjustSize(); + minusPriceButton->setWidth(plusPriceButton->getWidth()); + + placer(1, n + 2, minusPriceButton); + placer(2, n + 2, mItemPriceTextField, 3); + placer(5, n + 2, plusPriceButton); + placer(6, n + 2, mGPLabel); + + placer(1, n + 3, mItemPriceSlide, 7); + placer(4, n + 5, cancelButton); + placer(5, n + 5, okButton); + } + else + { + placer(4, n + 2, cancelButton); + placer(5, n + 2, okButton); + } + + reflowLayout(225, 0); + + resetAmount(); + + switch (usage) + { + case TradeAdd: + // TRANSLATORS: amount window message + setCaption(_("Select amount of items to trade.")); + break; + case ItemDrop: + // TRANSLATORS: amount window message + setCaption(_("Select amount of items to drop.")); + break; + case StoreAdd: + // TRANSLATORS: amount window message + setCaption(_("Select amount of items to store.")); + break; + case StoreRemove: + // TRANSLATORS: amount window message + setCaption(_("Select amount of items to retrieve.")); + break; + case ItemSplit: + // TRANSLATORS: amount window message + setCaption(_("Select amount of items to split.")); + break; + case ShopBuyAdd: + // TRANSLATORS: amount window message + setCaption(_("Add to buy shop.")); + break; + case ShopSellAdd: + // TRANSLATORS: amount window message + setCaption(_("Add to sell shop.")); + break; + default: + // TRANSLATORS: amount window message + setCaption(_("Unknown.")); + break; + } + + setLocationRelativeTo(getParentWindow()); + setVisible(true); + + mItemIcon->addMouseListener(this); +} + +ItemAmountWindow::~ItemAmountWindow() +{ + delete mItemPopup; + mItemPopup = nullptr; +} + +// Show ItemTooltip +void ItemAmountWindow::mouseMoved(gcn::MouseEvent &event) +{ + Window::mouseMoved(event); + + if (!viewport || !mItemPopup) + return; + + if (event.getSource() == mItemIcon) + { + mItemPopup->setItem(mItem); + mItemPopup->position(viewport->getMouseX(), viewport->getMouseY()); + } +} + +// Hide ItemTooltip +void ItemAmountWindow::mouseExited(gcn::MouseEvent &event A_UNUSED) +{ + if (mItemPopup) + mItemPopup->setVisible(false); +} + +void ItemAmountWindow::resetAmount() +{ + mItemAmountTextField->setValue(1); +} + +void ItemAmountWindow::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "cancel") + { + close(); + return; + } + else if (eventId == "ok") + { + if (mItemPriceTextField) + { + finish(mItem, mItemAmountTextField->getValue(), + mItemPriceTextField->getValue(), mUsage); + } + else + { + finish(mItem, mItemAmountTextField->getValue(), + 0, mUsage); + } + close(); + return; + } + else if (eventId == "itemType") + { + if (!mItemDropDown || !mItemsModal) + return; + + const int id = ItemDB::get(mItemsModal->getElementAt( + mItemDropDown->getSelected())).getId(); + + mItem = new Item(id, 10000); + + if (mUsage == ShopBuyAdd) + mMax = 10000; + else if (!mMax) + mMax = mItem->getQuantity(); + + mItemIcon->setImage(mItem->getImage()); + } + + int amount = mItemAmountTextField->getValue(); + + if (eventId == "inc" && amount < mMax) + amount++; + else if (eventId == "dec" && amount > 1) + amount--; + else if (eventId == "all") + amount = mMax; + else if (eventId == "slide") + amount = static_cast(mItemAmountSlide->getValue()); + mItemAmountTextField->setValue(amount); + mItemAmountSlide->setValue(amount); + + if (mItemPriceTextField && mItemPriceSlide) + { + if (mPrice > 7) + mPrice = 7; + else if (mPrice < 0) + mPrice = 0; + + int price = 0; + + if (eventId == "incPrice") + { + mPrice++; + price = static_cast(pow(10.0, mPrice)); + mItemPriceTextField->setValue(price); + mItemPriceSlide->setValue(price); + } + else if (eventId == "decPrice") + { + mPrice--; + price = static_cast(pow(10.0, mPrice)); + mItemPriceTextField->setValue(price); + mItemPriceSlide->setValue(price); + } + else if (eventId == "slidePrice") + { + price = static_cast(mItemPriceSlide->getValue()); + if (price) + mPrice = static_cast(log(static_cast(price))); + else + mPrice = 0; + mItemPriceTextField->setValue(price); + mItemPriceSlide->setValue(price); + } + } +} + +void ItemAmountWindow::close() +{ + keyboard.setEnabled(mEnabledKeyboard); + scheduleDelete(); +} + +void ItemAmountWindow::keyReleased(gcn::KeyEvent &keyEvent A_UNUSED) +{ + mItemAmountSlide->setValue(mItemAmountTextField->getValue()); +} + +void ItemAmountWindow::showWindow(const Usage usage, Window *const parent, + Item *const item, int maxRange) +{ + if (!item) + return; + + if (!maxRange) + maxRange = item->getQuantity(); + + if (usage != ShopBuyAdd && usage != ShopSellAdd && maxRange <= 1) + finish(item, maxRange, 0, usage); + else + new ItemAmountWindow(usage, parent, item, maxRange); +} diff --git a/src/gui/windows/itemamountwindow.h b/src/gui/windows/itemamountwindow.h new file mode 100644 index 000000000..1c95980fb --- /dev/null +++ b/src/gui/windows/itemamountwindow.h @@ -0,0 +1,126 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_ITEMAMOUNTWINDOW_H +#define GUI_ITEMAMOUNTWINDOW_H + +#include "gui/widgets/window.h" + +#include +#include + +class DropDown; +class Icon; +class IntTextField; +class Item; +class ItemsModal; +class ItemPopup; +class Label; +class Slider; + +/** + * Window used for selecting the amount of items to drop, trade or split. + * + * \ingroup Interface + */ +class ItemAmountWindow final : public Window, + public gcn::ActionListener, + public gcn::KeyListener +{ + public: + enum Usage + { + TradeAdd = 0, + ItemDrop, + StoreAdd, + StoreRemove, + ItemSplit, + ShopBuyAdd, + ShopSellAdd + }; + + A_DELETE_COPY(ItemAmountWindow) + + /** + * Called when receiving actions from widget. + */ + void action(const gcn::ActionEvent &event) override; + + /** + * Sets default amount value. + */ + void resetAmount(); + + // MouseListener + void mouseMoved(gcn::MouseEvent &event) override; + + void mouseExited(gcn::MouseEvent &event) override; + + /** + * Schedules the Item Amount window for deletion. + */ + void close(); + + void keyReleased(gcn::KeyEvent &keyEvent) override; + + /** + * Creates the dialog, or bypass it if there aren't enough items. + */ + static void showWindow(const Usage usage, Window *const parent, + Item *const item, int maxRange = 0); + + ~ItemAmountWindow(); + + private: + static void finish(Item *const item, const int amount, + const int price, const Usage usage); + + ItemAmountWindow(const Usage usage, Window *const parent, + Item *const item, const int maxRange = 0); + + IntTextField *mItemAmountTextField; /**< Item amount caption. */ + IntTextField *mItemPriceTextField; /**< Item price caption. */ + Label *mGPLabel; + Item *mItem; + Icon *mItemIcon; + + int mMax; + Usage mUsage; + ItemPopup *mItemPopup; + + /** + * Item Amount buttons. + */ + Slider *mItemAmountSlide; + + Slider *mItemPriceSlide; + + DropDown *mItemDropDown; + + ItemsModal *mItemsModal; + + int mPrice; + + bool mEnabledKeyboard; +}; + +#endif // GUI_ITEMAMOUNTWINDOW_H diff --git a/src/gui/windows/killstats.cpp b/src/gui/windows/killstats.cpp new file mode 100644 index 000000000..ee265e2b9 --- /dev/null +++ b/src/gui/windows/killstats.cpp @@ -0,0 +1,520 @@ +/* + * The ManaPlus Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 Andrei Karas + * Copyright (C) 2011-2013 The ManaPlus developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/killstats.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/label.h" +#include "gui/widgets/layout.h" + +#include "actorspritemanager.h" +#include "game.h" + +#include "being/localplayer.h" +#include "being/playerinfo.h" + +#include "utils/gettext.h" +#include "utils/stringutils.h" + +#include "debug.h" + +KillStats::KillStats() : + // TRANSLATORS: kill stats window name + Window(_("Kill stats"), false, nullptr, "killstats.xml"), + gcn::ActionListener(), + mKillCounter(0), + mExpCounter(0), + mKillTCounter(0), + mExpTCounter(0), + mKillTimer(0), + // TRANSLATORS: kill stats window button + mResetButton(new Button(this, _("Reset stats"), "reset", this)), + // TRANSLATORS: kill stats window button + mTimerButton(new Button(this, _("Reset timer"), "timer", this)), + mLine1(nullptr), + mLine2(nullptr), + mLine3(nullptr), + // TRANSLATORS: kill stats window label + mLine4(new Label(this, strprintf(_("Kills: %s, total exp: %s"), + "?", "?"))), + // TRANSLATORS: kill stats window label + mLine5(new Label(this, strprintf(_("Avg Exp: %s"), "?"))), + // TRANSLATORS: kill stats window label + mLine6(new Label(this, strprintf(_("No. of avg mob to next level: %s"), + "?"))), + // TRANSLATORS: kill stats window label + mLine7(new Label(this, strprintf(_("Kills/Min: %s, Exp/Min: %s"), + "?", "?"))), + mExpSpeed1Label(new Label(this, strprintf(ngettext( + // TRANSLATORS: kill stats window label + "Exp speed per %d min: %s", "Exp speed per %d min: %s", 1), 1, "?"))), + mExpTime1Label(new Label(this, strprintf(ngettext( + "Time for next level per %d min: %s", + "Time for next level per %d min: %s", 1), 1, "?"))), + mExpSpeed5Label(new Label(this, strprintf(ngettext( + "Exp speed per %d min: %s", "Exp speed per %d min: %s", 5), 5, "?"))), + mExpTime5Label(new Label(this, strprintf(ngettext( + "Time for next level per %d min: %s", + "Time for next level per %d min: %s", 5), 5, "?"))), + mExpSpeed15Label(new Label(this, strprintf(ngettext( + "Exp speed per %d min: %s", "Exp speed per %d min: %s", 15), + 15, "?"))), + mExpTime15Label(new Label(this, strprintf(ngettext( + "Time for next level per %d min: %s", + "Time for next level per %d min: %s", 15), 15, "?"))), + // TRANSLATORS: kill stats window label + mLastKillExpLabel(new Label(this, strprintf("%s ?", _("Last kill exp:")))), + mTimeBeforeJackoLabel(new Label(this, strprintf( + // TRANSLATORS: kill stats window label + "%s ?", _("Time before jacko spawn:")))), + m1minExpTime(0), + m1minExpNum(0), + m1minSpeed(0), + m5minExpTime(0), + m5minExpNum(0), + m5minSpeed(0), + m15minExpTime(0), + m15minExpNum(0), + m15minSpeed(0), + mJackoSpawnTime(0), + mJackoId(0), + mIsJackoAlive(false), + mIsJackoMustSpawn(true), + mIsJackoSpawnTimeUnknown(true) +{ + setWindowName("Kill stats"); + setCloseButton(true); + setResizable(true); + setSaveVisible(true); + setStickyButtonLock(true); + setDefaultSize(250, 250, 350, 300); + + listen(CHANNEL_ATTRIBUTES); + const int xp(PlayerInfo::getAttribute(PlayerInfo::EXP)); + int xpNextLevel(PlayerInfo::getAttribute(PlayerInfo::EXP_NEEDED)); + + if (!xpNextLevel) + xpNextLevel = 1; + + // TRANSLATORS: kill stats window label + mLine1 = new Label(this, strprintf(_("Level: %d at %f%%"), + player_node->getLevel(), static_cast(xp) + / static_cast(xpNextLevel) * 100.0)); + + // TRANSLATORS: kill stats window label + mLine2 = new Label(this, strprintf(_("Exp: %d/%d Left: %d"), + xp, xpNextLevel, xpNextLevel - xp)); + + // TRANSLATORS: kill stats window label + mLine3 = new Label(this, strprintf(_("1%% = %d exp, avg mob for 1%%: %s"), + xpNextLevel / 100, "?")); + + place(0, 0, mLine1, 6).setPadding(0); + place(0, 1, mLine2, 6).setPadding(0); + place(0, 2, mLine3, 6).setPadding(0); + place(0, 3, mLine4, 6).setPadding(0); + place(0, 4, mLine5, 6).setPadding(0); + place(0, 5, mLine6, 6).setPadding(0); + place(0, 6, mLine7, 6).setPadding(0); + + place(0, 7, mLastKillExpLabel, 6).setPadding(0); + place(0, 8, mTimeBeforeJackoLabel, 6).setPadding(0); + place(0, 9, mExpSpeed1Label, 6).setPadding(0); + place(0, 10, mExpTime1Label, 6).setPadding(0); + place(0, 11, mExpSpeed5Label, 6).setPadding(0); + place(0, 12, mExpTime5Label, 6).setPadding(0); + place(0, 13, mExpSpeed15Label, 6).setPadding(0); + place(0, 14, mExpTime15Label, 6).setPadding(0); + + place(5, 13, mTimerButton).setPadding(0); + place(5, 14, mResetButton).setPadding(0); + + loadWindowState(); + enableVisibleSound(true); +} + +KillStats::~KillStats() +{ +} + +void KillStats::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "reset") + { + mKillCounter = 0; + mExpCounter = 0; + mLine3->setCaption(strprintf("1%% = %d exp, avg mob for 1%%: %s", + PlayerInfo::getAttribute(PlayerInfo::EXP_NEEDED) / 100, "?")); + // TRANSLATORS: kill stats window label + mLine4->setCaption(strprintf(_("Kills: %s, total exp: %s"), "?", "?")); + // TRANSLATORS: kill stats window label + mLine5->setCaption(strprintf(_("Avg Exp: %s"), "?")); + mLine6->setCaption(strprintf( + // TRANSLATORS: kill stats window label + _("No. of avg mob to next level: %s"), "?")); + + resetTimes(); + } + else if (eventId == "timer") + { + mKillTimer = 0; + mKillTCounter = 0; + mExpTCounter = 0; + mLine7->setCaption(strprintf( + // TRANSLATORS: kill stats window label + _("Kills/Min: %s, Exp/Min: %s"), "?", "?")); + + resetTimes(); + } +} + +void KillStats::resetTimes() +{ + m1minExpTime = 0; + m1minExpNum = 0; + m1minSpeed = 0; + m5minExpTime = 0; + m5minExpNum = 0; + m5minSpeed = 0; + m15minExpTime = 0; + m15minExpNum = 0; + m15minSpeed = 0; +} + +void KillStats::gainXp(int xp) +{ + const int expNeed = PlayerInfo::getAttribute(PlayerInfo::EXP_NEEDED); + if (xp == expNeed) + xp = 0; + else if (!xp) + return; + + mKillCounter++; + mKillTCounter++; + + mExpCounter = mExpCounter + xp; + mExpTCounter = mExpTCounter + xp; + if (!mKillCounter) + mKillCounter = 1; + + const float AvgExp = static_cast(mExpCounter / mKillCounter); + int xpNextLevel(expNeed); + + if (mKillTimer == 0) + mKillTimer = cur_time; + + if (!xpNextLevel) + xpNextLevel = 1; + + double timeDiff = difftime(cur_time, mKillTimer) / 60; + + if (timeDiff <= 0.001) + timeDiff = 1; + + const int exp = PlayerInfo::getAttribute(PlayerInfo::EXP); + // TRANSLATORS: kill stats window label + mLine1->setCaption(strprintf(_("Level: %d at %f%%"), + player_node->getLevel(), static_cast(exp) + / static_cast(xpNextLevel) * 100.0)); + + // TRANSLATORS: kill stats window label + mLine2->setCaption(strprintf(_("Exp: %d/%d Left: %d"), exp, + xpNextLevel, xpNextLevel - exp)); + + if (AvgExp >= 0.001F && AvgExp <= 0.001F) + { + // TRANSLATORS: kill stats window label + mLine3->setCaption(strprintf(_("1%% = %d exp, avg mob for 1%%: %s"), + xpNextLevel / 100, "?")); + + // TRANSLATORS: kill stats window label + mLine5->setCaption(strprintf(_("Avg Exp: %s"), + toString(AvgExp).c_str())); + + mLine6->setCaption(strprintf( + // TRANSLATORS: kill stats window label + _("No. of avg mob to next level: %s"), "?")); + } + else + { + // TRANSLATORS: kill stats window label + mLine3->setCaption(strprintf(_("1%% = %d exp, avg mob for 1%%: %s"), + xpNextLevel / 100, toString((static_cast( + xpNextLevel) / 100) / AvgExp).c_str())); + + // TRANSLATORS: kill stats window label + mLine5->setCaption(strprintf(_("Avg Exp: %s"), + toString(AvgExp).c_str())); + + // TRANSLATORS: kill stats window label + mLine6->setCaption(strprintf(_("No. of avg mob to next level: %s"), + toString(static_cast(xpNextLevel - exp) / AvgExp).c_str())); + } + // TRANSLATORS: kill stats window label + mLine4->setCaption(strprintf(_("Kills: %s, total exp: %s"), + toString(mKillCounter).c_str(), toString(mExpCounter).c_str())); + + // TRANSLATORS: kill stats window label + mLine7->setCaption(strprintf(_("Kills/Min: %s, Exp/Min: %s"), + toString(mKillTCounter / timeDiff).c_str(), + toString(mExpTCounter / timeDiff).c_str())); + + // TRANSLATORS: kill stats window label + mLastKillExpLabel->setCaption(strprintf("%s %d", _("Last kill exp:"), xp)); + + recalcStats(); + update(); +} + +void KillStats::recalcStats() +{ + BLOCK_START("KillStats::recalcStats") + const int curTime = cur_time; + + // Need Update Exp Counter + if (curTime - m1minExpTime > 60) + { + const int newExp = PlayerInfo::getAttribute(PlayerInfo::EXP); + if (m1minExpTime != 0) + m1minSpeed = newExp - m1minExpNum; + else + m1minSpeed = 0; + m1minExpTime = curTime; + m1minExpNum = newExp; + } + + if (curTime - m5minExpTime > 60*5) + { + const int newExp = PlayerInfo::getAttribute(PlayerInfo::EXP); + if (m5minExpTime != 0) + m5minSpeed = newExp - m5minExpNum; + else + m5minSpeed = 0; + m5minExpTime = curTime; + m5minExpNum = newExp; + } + + if (curTime - m15minExpTime > 60*15) + { + const int newExp = PlayerInfo::getAttribute(PlayerInfo::EXP); + if (m15minExpTime != 0) + m15minSpeed = newExp - m15minExpNum; + else + m15minSpeed = 0; + m15minExpTime = curTime; + m15minExpNum = newExp; + } + validateJacko(); + BLOCK_END("KillStats::recalcStats") +} + +void KillStats::update() +{ + BLOCK_START("KillStats::update") + + mExpSpeed1Label->setCaption(strprintf(ngettext("Exp speed per %d min: %s", + "Exp speed per %d min: %s", 1), 1, toString(m1minSpeed).c_str())); + + if (m1minSpeed != 0) + { + // TRANSLATORS: kill stats window label + mExpTime1Label->setCaption(strprintf(_(" Time for next level: %s"), + toString(static_cast((PlayerInfo::getAttribute( + PlayerInfo::EXP_NEEDED) - PlayerInfo::getAttribute( + PlayerInfo::EXP)) / m1minSpeed)).c_str())); + } + else + { + mExpTime1Label->setCaption(strprintf( + // TRANSLATORS: kill stats window label + _(" Time for next level: %s"), "?")); + } + mExpTime1Label->adjustSize(); + + mExpSpeed5Label->setCaption(strprintf(ngettext("Exp speed per %d min: %s", + "Exp speed per %d min: %s", 5), 5, toString(m5minSpeed / 5).c_str())); + mExpSpeed5Label->adjustSize(); + + if (m5minSpeed != 0) + { + // TRANSLATORS: kill stats window label + mExpTime5Label->setCaption(strprintf(_(" Time for next level: %s"), + toString(static_cast((PlayerInfo::getAttribute( + PlayerInfo::EXP_NEEDED) - PlayerInfo::getAttribute( + PlayerInfo::EXP)) / m5minSpeed * 5)).c_str())); + } + else + { + mExpTime5Label->setCaption(strprintf( + // TRANSLATORS: kill stats window label + _(" Time for next level: %s"), "?")); + } + mExpTime5Label->adjustSize(); + + + mExpSpeed15Label->setCaption(strprintf(ngettext("Exp speed per %d min: %s", + "Exp speed per %d min: %s", 15), 15, toString( + m15minSpeed / 15).c_str())); + mExpSpeed15Label->adjustSize(); + + if (m15minSpeed != 0) + { + // TRANSLATORS: kill stats window label + mExpTime15Label->setCaption(strprintf(_(" Time for next level: %s"), + toString(static_cast((PlayerInfo::getAttribute( + PlayerInfo::EXP_NEEDED) - PlayerInfo::getAttribute( + PlayerInfo::EXP)) / m15minSpeed * 15)).c_str())); + } + else + { + mExpTime15Label->setCaption(strprintf( + // TRANSLATORS: kill stats window label + _(" Time for next level: %s"), "?")); + } + + validateJacko(); + updateJackoLabel(); + BLOCK_END("KillStats::update") +} + +void KillStats::updateJackoLabel() +{ + if (mIsJackoAlive) + { + mTimeBeforeJackoLabel->setCaption(strprintf("%s jacko alive", + // TRANSLATORS: kill stats window label + _("Time before jacko spawn:"))); + } + else if (mIsJackoSpawnTimeUnknown && mJackoSpawnTime != 0) + { + // TRANSLATORS: kill stats window label + mTimeBeforeJackoLabel->setCaption(strprintf( + // TRANSLATORS: kill stats window label + _("%s %d?"), _("Time before jacko spawn:"), + mJackoSpawnTime - cur_time)); + } + else if (mIsJackoMustSpawn) + { + mTimeBeforeJackoLabel->setCaption(strprintf("%s %s", + // TRANSLATORS: kill stats window label + _("Time before jacko spawn:"), _("jacko spawning"))); + } + else + { + mTimeBeforeJackoLabel->setCaption(strprintf("%s %d", + // TRANSLATORS: kill stats window label + _("Time before jacko spawn:"), mJackoSpawnTime - cur_time)); + } +} + +void KillStats::jackoDead(const int id) +{ + if (id == mJackoId && mIsJackoAlive) + { + mIsJackoAlive = false; + mJackoSpawnTime = cur_time + 60*4; + mIsJackoSpawnTimeUnknown = false; + updateJackoLabel(); + } +} + +void KillStats::jackoAlive(const int id) +{ + if (!mIsJackoAlive) + { + mJackoId = id; + mIsJackoAlive = true; + mIsJackoMustSpawn = false; + mJackoSpawnTime = 0; + mIsJackoSpawnTimeUnknown = false; + updateJackoLabel(); + } +} + +void KillStats::validateJacko() +{ + if (!actorSpriteManager || !player_node) + return; + + const Map *const currentMap = Game::instance()->getCurrentMap(); + if (currentMap) + { + if (currentMap->getProperty("_realfilename") == "018-1" + || currentMap->getProperty("_realfilename") == "maps/018-1.tmx") + { + if (player_node->getTileX() >= 167 + && player_node->getTileX() <= 175 + && player_node->getTileY() >= 21 + && player_node->getTileY() <= 46) + { + const Being *const dstBeing + = actorSpriteManager->findBeingByName( + "Jack O", Being::MONSTER); + if (mIsJackoAlive && !dstBeing) + { + mIsJackoAlive = false; + mJackoSpawnTime = cur_time + 60*4; + mIsJackoSpawnTimeUnknown = true; + } + } + } + + if (!mIsJackoAlive && cur_time > mJackoSpawnTime + 15) + mIsJackoMustSpawn = true; + } +} + +void KillStats::processEvent(const Channels channel A_UNUSED, + const DepricatedEvent &event) +{ + if (event.getName() == EVENT_UPDATEATTRIBUTE) + { + const int id = event.getInt("id"); + if (id == PlayerInfo::EXP || id == PlayerInfo::EXP_NEEDED) + { + gainXp(event.getInt("newValue") - event.getInt("oldValue")); + } + else if (id == PlayerInfo::LEVEL) + { + mKillCounter = 0; + mKillTCounter = 0; + mExpCounter = 0; + mExpTCounter = 0; + mLine3->setCaption(strprintf("1%% = %d exp, avg mob for 1%%: %s", + PlayerInfo::getAttribute(PlayerInfo::EXP_NEEDED) / 100, "?")); + mLine4->setCaption(strprintf( + // TRANSLATORS: kill stats window label + _("Kills: %s, total exp: %s"), "?", "?")); + // TRANSLATORS: kill stats window label + mLine5->setCaption(strprintf(_("Avg Exp: %s"), "?")); + mLine6->setCaption(strprintf( + // TRANSLATORS: kill stats window label + _("No. of avg mob to next level: %s"), "?")); + mLine7->setCaption(strprintf( + // TRANSLATORS: kill stats window label + _("Kills/Min: %s, Exp/Min: %s"), "?", "?")); + + resetTimes(); + } + } +} diff --git a/src/gui/windows/killstats.h b/src/gui/windows/killstats.h new file mode 100644 index 000000000..a5b59affb --- /dev/null +++ b/src/gui/windows/killstats.h @@ -0,0 +1,132 @@ +/* + * The ManaPlus Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 Andrei Karas + * Copyright (C) 2011-2013 The ManaPlus developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_KILLSTATS_H +#define GUI_KILLSTATS_H + +#include + +#include "depricatedlistener.h" + +#include "gui/widgets/window.h" + +class Label; +class Button; + +class KillStats final : public Window, + private gcn::ActionListener, + public DepricatedListener +{ + public: + /** + * Constructor. + */ + KillStats(); + + A_DELETE_COPY(KillStats) + + /** + * Destructor. + */ + ~KillStats(); + + /** + * Stuff. + */ + void action(const gcn::ActionEvent &event) override; + + void gainXp(int Xp); + + /** + * Recalc stats if needed + */ + void recalcStats(); + + /** + * Updates this dialog + */ + void update(); + + /** + * Updates jacko info + */ + void updateJackoLabel(); + + void jackoDead(const int id); + + void jackoAlive(const int id); + + void processEvent(const Channels channel A_UNUSED, + const DepricatedEvent &event) override; + + void resetTimes(); + + private: + void validateJacko(); + + int mKillCounter; /**< Session Kill counter. */ + int mExpCounter; /**< Session Exp counter. */ + int mKillTCounter; /**< Timer Kill counter. */ + int mExpTCounter; /**< Timer Exp counter. */ + time_t mKillTimer; /**< Timer for kill stats. */ + Button *mResetButton; + Button *mTimerButton; + Label *mLine1; + Label *mLine2; + Label *mLine3; + Label *mLine4; + Label *mLine5; + Label *mLine6; + Label *mLine7; + + Label *mExpSpeed1Label; + Label *mExpTime1Label; + Label *mExpSpeed5Label; + Label *mExpTime5Label; + Label *mExpSpeed15Label; + Label *mExpTime15Label; + + Label *mLastKillExpLabel; + Label *mTimeBeforeJackoLabel; + + int m1minExpTime; + int m1minExpNum; + int m1minSpeed; + + int m5minExpTime; + int m5minExpNum; + int m5minSpeed; + + int m15minExpTime; + int m15minExpNum; + int m15minSpeed; + + int mJackoSpawnTime; + int mJackoId; + bool mIsJackoAlive; + bool mIsJackoMustSpawn; + bool mIsJackoSpawnTimeUnknown; +}; + +extern KillStats *killStats; + +#endif // GUI_KILLSTATS_H diff --git a/src/gui/windows/logindialog.cpp b/src/gui/windows/logindialog.cpp new file mode 100644 index 000000000..883c4606d --- /dev/null +++ b/src/gui/windows/logindialog.cpp @@ -0,0 +1,413 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/logindialog.h" + +#include "client.h" +#include "configuration.h" + +#include "input/keydata.h" +#include "input/keyevent.h" + +#include "gui/windows/confirmdialog.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/checkbox.h" +#include "gui/widgets/dropdown.h" +#include "gui/widgets/label.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/passwordfield.h" + +#include "net/charserverhandler.h" +#include "net/logindata.h" +#include "net/loginhandler.h" +#include "net/net.h" + +#include "utils/gettext.h" +#include "utils/paths.h" +#include "utils/process.h" + +#include "debug.h" + +std::string LoginDialog::savedPassword(""); +std::string LoginDialog::savedPasswordKey(""); + +struct OpenUrlListener : public gcn::ActionListener +{ + OpenUrlListener() : + gcn::ActionListener(), + url() + { + } + + A_DELETE_COPY(OpenUrlListener) + + void action(const gcn::ActionEvent &event) override + { + if (event.getId() == "yes") + openBrowser(url); + } + + std::string url; +} urlListener; + +const char *UPDATE_TYPE_TEXT[3] = +{ + // TRANSLATORS: update type + N_("Normal"), + // TRANSLATORS: update type + N_("Auto Close"), + // TRANSLATORS: update type + N_("Skip"), +}; + +class UpdateTypeModel final : public gcn::ListModel +{ + public: + UpdateTypeModel() + { } + + A_DELETE_COPY(UpdateTypeModel) + + ~UpdateTypeModel() + { } + + int getNumberOfElements() override + { + return 3; + } + + std::string getElementAt(int i) override + { + if (i >= getNumberOfElements() || i < 0) + return "???"; + return gettext(UPDATE_TYPE_TEXT[i]); + } +}; + +class UpdateListModel final : public gcn::ListModel +{ + public: + explicit UpdateListModel(LoginData *const data) : + gcn::ListModel(), + mLoginData(data) + { + } + + A_DELETE_COPY(UpdateListModel) + + ~UpdateListModel() + { } + + int getNumberOfElements() override + { + if (!mLoginData) + return 0; + return static_cast(mLoginData->updateHosts.size()); + } + + std::string getElementAt(int i) override + { + if (!mLoginData || i >= getNumberOfElements() || i < 0) + return "???"; + return mLoginData->updateHosts[i]; + } + + protected: + LoginData *mLoginData; +}; + +LoginDialog::LoginDialog(LoginData *const data, std::string serverName, + std::string *const updateHost): + // TRANSLATORS: login dialog name + Window(_("Login"), false, nullptr, "login.xml"), + gcn::ActionListener(), + gcn::KeyListener(), + mLoginData(data), + mUserField(new TextField(this, mLoginData->username)), + mPassField(new PasswordField(this, mLoginData->password)), + // TRANSLATORS: login dialog label + mKeepCheck(new CheckBox(this, _("Remember username"), + mLoginData->remember)), + // TRANSLATORS: login dialog label + mUpdateTypeLabel(new Label(this, _("Update:"))), + mUpdateHostLabel(nullptr), + mUpdateTypeModel(new UpdateTypeModel), + mUpdateTypeDropDown(new DropDown(this, mUpdateTypeModel)), + // TRANSLATORS: login dialog button + mServerButton(new Button(this, _("Change Server"), "server", this)), + // TRANSLATORS: login dialog button + mLoginButton(new Button(this, _("Login"), "login", this)), + // TRANSLATORS: login dialog button + mRegisterButton(new Button(this, _("Register"), "register", this)), + // TRANSLATORS: login dialog checkbox + mCustomUpdateHost(new CheckBox(this, _("Custom update host"), + mLoginData->updateType & LoginData::Upd_Custom, this, "customhost")), + mUpdateHostText(new TextField(this, serverConfig.getValue( + "customUpdateHost", ""))), + mUpdateListModel(nullptr), + mUpdateHostDropDown(nullptr), + mUpdateHost(updateHost), + mServerName(serverName) +{ + setCloseButton(true); + + Net::getCharServerHandler()->clear(); + + // TRANSLATORS: login dialog label + Label *const serverLabel1 = new Label(this, _("Server:")); + Label *const serverLabel2 = new Label(this, serverName); + serverLabel2->adjustSize(); + // TRANSLATORS: login dialog label + Label *const userLabel = new Label(this, _("Name:")); + // TRANSLATORS: login dialog label + Label *const passLabel = new Label(this, _("Password:")); + if (mLoginData && mLoginData->updateHosts.size() > 1) + { + // TRANSLATORS: login dialog label + mUpdateHostLabel = new Label(this, strprintf(_("Update host: %s"), + mLoginData->updateHost.c_str())); + mUpdateListModel = new UpdateListModel(mLoginData); + mUpdateHostDropDown = new DropDown(this, mUpdateListModel, + false, false, this, "updateselect"); + const std::string str = serverConfig.getValue("updateHost2", ""); + if (!str.empty()) + mUpdateHostDropDown->setSelectedString(str); + } + else + { + mUpdateHostLabel = nullptr; + mUpdateListModel = nullptr; + mUpdateHostDropDown = nullptr; + } + mUpdateHostText->adjustSize(); + + if (mPassField->getText().empty() && LoginDialog::savedPassword != "") + mPassField->setText(LoginDialog::savedPassword); + + mUpdateTypeDropDown->setActionEventId("updatetype"); + mUpdateTypeDropDown->setSelected((mLoginData->updateType + | LoginData::Upd_Custom) ^ LoginData::Upd_Custom); + + if (!mCustomUpdateHost->isSelected()) + mUpdateHostText->setVisible(false); + + mUserField->setActionEventId("login"); + mPassField->setActionEventId("login"); + + mUserField->addKeyListener(this); + mPassField->addKeyListener(this); + mUserField->addActionListener(this); + mPassField->addActionListener(this); + + place(0, 0, serverLabel1); + place(1, 0, serverLabel2, 8); + place(0, 1, userLabel); + place(1, 1, mUserField, 8); + place(0, 2, passLabel); + place(1, 2, mPassField, 8); + place(0, 6, mUpdateTypeLabel, 1); + place(1, 6, mUpdateTypeDropDown, 8); + int n = 7; + if (mUpdateHostLabel) + { + place(0, 7, mUpdateHostLabel, 9); + place(0, 8, mUpdateHostDropDown, 9); + n += 2; + } + place(0, n, mCustomUpdateHost, 9); + place(0, n + 1, mUpdateHostText, 9); + place(0, n + 2, mKeepCheck, 9); + place(0, n + 3, mRegisterButton).setHAlign(LayoutCell::LEFT); + place(2, n + 3, mServerButton); + place(3, n + 3, mLoginButton); + + addKeyListener(this); + if (mUpdateHostLabel) + setContentSize(310, 250); + else + setContentSize(310, 200); + + reflowLayout(); + center(); + setVisible(true); + + if (mUserField->getText().empty()) + mUserField->requestFocus(); + else + mPassField->requestFocus(); + + mLoginButton->setEnabled(canSubmit()); + mRegisterButton->setEnabled(Net::getLoginHandler()->isRegistrationEnabled() + || !mLoginData->registerUrl.empty()); +} + +LoginDialog::~LoginDialog() +{ + delete mUpdateTypeModel; + mUpdateTypeModel = nullptr; + delete mUpdateListModel; + mUpdateListModel = nullptr; +} + +void LoginDialog::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "login" && canSubmit()) + { + prepareUpdate(); + mLoginData->registerLogin = false; + client->setState(STATE_LOGIN_ATTEMPT); + } + else if (eventId == "server") + { + close(); + } + else if (eventId == "register") + { + if (Net::getLoginHandler()->isRegistrationEnabled()) + { + prepareUpdate(); + client->setState(STATE_REGISTER_PREP); + } + else if (!mLoginData->registerUrl.empty()) + { + const std::string &url = mLoginData->registerUrl; + urlListener.url = url; + // TRANSLATORS: question dialog + ConfirmDialog *const confirmDlg = new ConfirmDialog( + _("Open register url"), url, SOUND_REQUEST, false, true); + confirmDlg->addActionListener(&urlListener); + } + } + else if (eventId == "customhost") + { + mUpdateHostText->setVisible(mCustomUpdateHost->isSelected()); + } + else if (eventId == "updateselect") + { + mCustomUpdateHost->setSelected(false); + mUpdateHostText->setVisible(false); + } +} + +void LoginDialog::keyPressed(gcn::KeyEvent &keyEvent) +{ + if (keyEvent.isConsumed()) + { + mLoginButton->setEnabled(canSubmit()); + return; + } + + const int actionId = static_cast( + &keyEvent)->getActionId(); + if (actionId == static_cast(Input::KEY_GUI_CANCEL)) + { + action(gcn::ActionEvent(nullptr, mServerButton->getActionEventId())); + } + else if (actionId == static_cast(Input::KEY_GUI_SELECT) + || actionId == static_cast(Input::KEY_GUI_SELECT2)) + { + action(gcn::ActionEvent(nullptr, mLoginButton->getActionEventId())); + } + else + { + mLoginButton->setEnabled(canSubmit()); + } +} + +bool LoginDialog::canSubmit() const +{ + return !mUserField->getText().empty() && + !mPassField->getText().empty() && + client->getState() == STATE_LOGIN; +} + +void LoginDialog::prepareUpdate() +{ + mLoginData->username = mUserField->getText(); + mLoginData->password = mPassField->getText(); + mLoginData->remember = mKeepCheck->isSelected(); + int updateType = mUpdateTypeDropDown->getSelected(); + + if (mCustomUpdateHost->isSelected() + && !mUpdateHostText->getText().empty()) + { + updateType |= LoginData::Upd_Custom; + serverConfig.setValue("customUpdateHost", + mUpdateHostText->getText()); + + if (checkPath(mUpdateHostText->getText())) + { + mLoginData->updateHost = mUpdateHostText->getText(); + *mUpdateHost = mUpdateHostText->getText(); + } + else + { + mLoginData->updateHost.clear(); + (*mUpdateHost).clear(); + } + } + else + { + std::string str; + if (mUpdateHostDropDown) + { + str = mUpdateHostDropDown->getSelectedString(); + } + else if (mLoginData->updateHost.empty() + && !mLoginData->updateHosts.empty()) + { + str = mLoginData->updateHosts[0]; + } + serverConfig.setValue("updateHost2", str); + if (!str.empty() && checkPath(str)) + { + mLoginData->updateHost = str; + *mUpdateHost = str; + } + else + { + mLoginData->updateHost.clear(); + (*mUpdateHost).clear(); + } + } + + mLoginData->updateType = updateType; + serverConfig.setValue("updateType", updateType); + + mRegisterButton->setEnabled(false); + mServerButton->setEnabled(false); + mLoginButton->setEnabled(false); + + LoginDialog::savedPassword = mPassField->getText(); + if (mLoginData->remember) + LoginDialog::savedPasswordKey = mServerName; + else + LoginDialog::savedPasswordKey = "-"; +} + +void LoginDialog::close() +{ + client->setState(STATE_SWITCH_SERVER); + Window::close(); +} diff --git a/src/gui/windows/logindialog.h b/src/gui/windows/logindialog.h new file mode 100644 index 000000000..fee0d4016 --- /dev/null +++ b/src/gui/windows/logindialog.h @@ -0,0 +1,108 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_LOGINDIALOG_H +#define GUI_LOGINDIALOG_H + +#include "gui/widgets/window.h" + +#include +#include + +#include + +class Button; +class CheckBox; +class DropDown; +class Label; +class LoginData; +class TextField; +class UpdateListModel; +class UpdateTypeModel; + +/** + * The login dialog. + * + * \ingroup Interface + */ +class LoginDialog final : public Window, public gcn::ActionListener, + public gcn::KeyListener +{ + public: + /** + * Constructor + * + * @see Window::Window + */ + LoginDialog(LoginData *const data, std::string serverName, + std::string *const updateHost); + + A_DELETE_COPY(LoginDialog) + + ~LoginDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + /** + * Called when a key is pressed in one of the text fields. + */ + void keyPressed(gcn::KeyEvent &keyEvent) override; + + void close() override; + + static std::string savedPasswordKey; + static std::string savedPassword; + + private: + /** + * Returns whether submit can be enabled. This is true in the login + * state, when all necessary fields have some text. + */ + bool canSubmit() const; + + void prepareUpdate(); + + LoginData *mLoginData; + + TextField *mUserField; + TextField *mPassField; + CheckBox *mKeepCheck; + Label *mUpdateTypeLabel; + Label *mUpdateHostLabel; + UpdateTypeModel *mUpdateTypeModel; + DropDown *mUpdateTypeDropDown; + Button *mServerButton; + Button *mLoginButton; + Button *mRegisterButton; + CheckBox *mCustomUpdateHost; + TextField *mUpdateHostText; + UpdateListModel *mUpdateListModel; + DropDown *mUpdateHostDropDown; + + std::string *mUpdateHost; + std::string mServerName; +}; + +#endif // GUI_LOGINDIALOG_H diff --git a/src/gui/windows/minimap.cpp b/src/gui/windows/minimap.cpp new file mode 100644 index 000000000..9adadd1e0 --- /dev/null +++ b/src/gui/windows/minimap.cpp @@ -0,0 +1,485 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/minimap.h" + +#include "actorspritemanager.h" +#include "client.h" +#include "configuration.h" +#include "party.h" + +#include "being/localplayer.h" + +#include "gui/viewport.h" +#include "gui/textpopup.h" + +#include "gui/windows/setup.h" + +#include "resources/image.h" +#include "resources/imagehelper.h" +#include "resources/resourcemanager.h" + +#include "utils/gettext.h" +#include "utils/sdlcheckutils.h" + +#include "debug.h" + +bool Minimap::mShow = true; + +Minimap::Minimap() : + // TRANSLATORS: mini map window name + Window(_("Map"), false, nullptr, "map.xml"), + mWidthProportion(0.5), + mHeightProportion(0.5), + mMapImage(nullptr), + mMapOriginX(0), + mMapOriginY(0), + mTextPopup(new TextPopup), + mCustomMapImage(false), + mAutoResize(config.getBoolValue("autoresizeminimaps")) +{ + setWindowName("Minimap"); + mShow = config.getValueBool(getWindowName() + "Show", true); + + config.addListener("autoresizeminimaps", this); + + setDefaultSize(5, 25, 100, 100); + // set this to false as the minimap window size is changed + // depending on the map size + setResizable(true); + if (setupWindow) + setupWindow->registerWindowForReset(this); + + setDefaultVisible(true); + setSaveVisible(true); + + setStickyButton(true); + setSticky(false); + + loadWindowState(); + setVisible(mShow, isSticky()); + enableVisibleSound(true); +} + +Minimap::~Minimap() +{ + config.setValue(getWindowName() + "Show", mShow); + config.removeListeners(this); + + if (mMapImage) + { + if (mCustomMapImage) + delete mMapImage; + else + mMapImage->decRef(); + mMapImage = nullptr; + } + delete mTextPopup; + mTextPopup = nullptr; +} + +void Minimap::setMap(const Map *const map) +{ + std::string caption; + + if (map) + caption = map->getName(); + + if (caption.empty()) + { + // TRANSLATORS: mini map window name + caption = _("Map"); + } + + setCaption(caption); + + // Adapt the image + if (mMapImage) + { + if (mCustomMapImage) + delete mMapImage; + else + mMapImage->decRef(); + mMapImage = nullptr; + } + + if (map) + { + if (config.getBoolValue("showExtMinimaps")) + { + SDL_Surface *const surface = MSDL_CreateRGBSurface(SDL_SWSURFACE, + map->getWidth(), map->getHeight(), 32, + 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000); + if (!surface) + { + if (!isSticky()) + setVisible(false); + return; + } + + // I'm not sure if the locks are necessary since it's a SWSURFACE + SDL_LockSurface(surface); + int* data = static_cast(surface->pixels); + if (!data) + { + if (!isSticky()) + setVisible(false); + return; + } + const int size = surface->h * surface->w; + const int mask = (Map::BLOCKMASK_WALL | Map::BLOCKMASK_AIR + | Map::BLOCKMASK_WATER); + + for (int ptr = 0; ptr < size; ptr ++) + *(data ++) = -!(map->mMetaTiles[ptr].blockmask & mask); + + SDL_UnlockSurface(surface); + + mMapImage = imageHelper->load(surface); + mMapImage->setAlpha(client->getGuiAlpha()); + mCustomMapImage = true; + MSDL_FreeSurface(surface); + } + else + { + std::string tempname = paths.getStringValue("minimaps").append( + map->getFilename()).append(".png"); + ResourceManager *const resman = ResourceManager::getInstance(); + + std::string minimapName = map->getProperty("minimap"); + + if (minimapName.empty() && resman->exists(tempname)) + minimapName = tempname; + + if (minimapName.empty()) + { + tempname = std::string("graphics/minimaps/").append( + map->getFilename()).append(".png"); + if (resman->exists(tempname)) + minimapName = tempname; + } + + mMapImage = resman->getImage(minimapName); + mCustomMapImage = false; + } + } + + if (mMapImage && map) + { + const int width = mMapImage->mBounds.w + 2 * getPadding(); + const int height = mMapImage->mBounds.h + + getTitleBarHeight() + getPadding(); + const int mapWidth = mMapImage->mBounds.w < 100 ? width : 100; + const int mapHeight = mMapImage->mBounds.h < 100 ? height : 100; + const int minWidth = mapWidth > 310 ? 310 : mapWidth; + const int minHeight = mapHeight > 220 ? 220 : mapHeight; + + setMinWidth(minWidth); + setMinHeight(minHeight); + + mWidthProportion = static_cast( + mMapImage->mBounds.w) / static_cast(map->getWidth()); + mHeightProportion = static_cast( + mMapImage->mBounds.h) / static_cast(map->getHeight()); + + setMaxWidth(width); + setMaxHeight(height); + if (mAutoResize) + { + setWidth(width); + setHeight(height); + } + + const gcn::Rectangle &rect = mDimension; + setDefaultSize(rect.x, rect.y, rect.width, rect.height); + resetToDefaultSize(); + + if (mShow) + setVisible(true); + } + else + { + if (!isSticky()) + setVisible(false); + } +} + +void Minimap::toggle() +{ + setVisible(!isWindowVisible(), isSticky()); + mShow = isWindowVisible(); +} + +void Minimap::draw(gcn::Graphics *graphics) +{ + BLOCK_START("Minimap::draw") + Window::draw(graphics); + + if (!userPalette || !player_node || !viewport) + { + BLOCK_END("Minimap::draw") + return; + } + + Graphics *const graph = static_cast(graphics); + + const gcn::Rectangle a = getChildrenArea(); + + graphics->pushClipArea(a); + + if (!actorSpriteManager) + { + BLOCK_END("Minimap::draw") + return; + } + + mMapOriginX = 0; + mMapOriginY = 0; + + if (mMapImage) + { + const SDL_Rect &rect = mMapImage->mBounds; + const int w = rect.w; + const int h = rect.h; + if (w > a.width || h > a.height) + { + const Vector &p = player_node->getPosition(); + mMapOriginX = (a.width / 2) - (p.x + static_cast( + viewport->getCameraRelativeX()) * mWidthProportion) / 32; + + mMapOriginY = (a.height / 2) - (p.y + static_cast( + viewport->getCameraRelativeY()) * mHeightProportion) / 32; + + const int minOriginX = a.width - w; + const int minOriginY = a.height - h; + + if (mMapOriginX < minOriginX) + mMapOriginX = minOriginX; + if (mMapOriginY < minOriginY) + mMapOriginY = minOriginY; + if (mMapOriginX > 0) + mMapOriginX = 0; + if (mMapOriginY > 0) + mMapOriginY = 0; + } + + graph->drawImage(mMapImage, mMapOriginX, mMapOriginY); + } + + const ActorSprites &actors = actorSpriteManager->getAll(); + FOR_EACH (ActorSpritesConstIterator, it, actors) + { + if (!(*it) || (*it)->getType() == ActorSprite::FLOOR_ITEM) + continue; + + const Being *const being = static_cast(*it); + if (!being) + continue; + + int dotSize = 2; + int type = UserPalette::PC; + + if (being == player_node) + { + type = UserPalette::SELF; + dotSize = 3; + } + else if (being->isGM()) + { + type = UserPalette::GM; + } + else if (being->getGuild() == player_node->getGuild() + || being->getGuildName() == player_node->getGuildName()) + { + type = UserPalette::GUILD; + } + else + { + switch (being->getType()) + { + case ActorSprite::MONSTER: + type = UserPalette::MONSTER; + break; + + case ActorSprite::NPC: + type = UserPalette::NPC; + break; + + case ActorSprite::AVATAR: + case ActorSprite::UNKNOWN: + case ActorSprite::PLAYER: + case ActorSprite::FLOOR_ITEM: + case ActorSprite::PORTAL: + case ActorSprite::PET: + default: + continue; + } + } + + if (userPalette) + graphics->setColor(userPalette->getColor(type)); + + const int offsetHeight = static_cast(static_cast( + dotSize - 1) * mHeightProportion); + const int offsetWidth = static_cast(static_cast( + dotSize - 1) * mWidthProportion); + const Vector &pos = being->getPosition(); + + graphics->fillRectangle(gcn::Rectangle( + static_cast(pos.x * mWidthProportion) / 32 + + mMapOriginX - offsetWidth, + static_cast(pos.y * mHeightProportion) / 32 + + mMapOriginY - offsetHeight, dotSize, dotSize)); + } + + if (player_node->isInParty()) + { + const Party *const party = player_node->getParty(); + if (party) + { + const PartyMember *const m = party->getMember( + player_node->getName()); + const Party::MemberList *const members = party->getMembers(); + if (m && members) + { + const std::string curMap = m->getMap(); + Party::MemberList::const_iterator it = members->begin(); + const Party::MemberList::const_iterator + it_end = members->end(); + while (it != it_end) + { + const PartyMember *const member = *it; + if (member && member->getMap() == curMap + && member->getOnline() && member != m) + { + if (userPalette) + { + graphics->setColor(userPalette->getColor( + UserPalette::PARTY)); + } + + const int offsetHeight = static_cast( + mHeightProportion); + const int offsetWidth = static_cast( + mWidthProportion); + + graphics->fillRectangle(gcn::Rectangle( + static_cast(member->getX() + * mWidthProportion) + mMapOriginX - offsetWidth, + static_cast(member->getY() + * mHeightProportion) + mMapOriginY - offsetHeight, + 2, 2)); + } + ++ it; + } + } + } + } + + const Vector &pos = player_node->getPosition(); + + const int gw = graph->getWidth(); + const int gh = graph->getHeight(); + int x = static_cast((pos.x - (gw / 2) + + viewport->getCameraRelativeX()) + * mWidthProportion) / 32 + mMapOriginX; + int y = static_cast((pos.y - (gh / 2) + + viewport->getCameraRelativeY()) + * mHeightProportion) / 32 + mMapOriginY; + + const int w = static_cast(static_cast( + gw) * mWidthProportion / 32); + const int h = static_cast(static_cast( + gh) * mHeightProportion / 32); + + if (w <= a.width) + { + if (x < 0 && w) + x = 0; + if (x + w > a.width) + x = a.width - w; + } + if (h <= a.height) + { + if (y < 0 && h) + y = 0; + if (y + h > a.height) + y = a.height - h; + } + + graphics->setColor(userPalette->getColor(UserPalette::PC)); + graphics->drawRectangle(gcn::Rectangle(x, y, w, h)); + graphics->popClipArea(); + BLOCK_END("Minimap::draw") +} + +void Minimap::mouseReleased(gcn::MouseEvent &event) +{ + Window::mouseReleased(event); + + if (!player_node || !viewport) + return; + + if (event.getButton() == gcn::MouseEvent::LEFT) + { + int x = event.getX(); + int y = event.getY(); + screenToMap(x, y); + + player_node->navigateTo(x, y); + } + else if (event.getButton() == gcn::MouseEvent::RIGHT) + { + int x = event.getX(); + int y = event.getY(); + screenToMap(x, y); + viewport->showMapPopup(x, y); + } +} + +void Minimap::mouseMoved(gcn::MouseEvent &event) +{ + Window::mouseMoved(event); + const int x = event.getX(); + const int y = event.getY(); + const gcn::Rectangle &rect = mDimension; + mTextPopup->show(x + rect.x, y + rect.y, mCaption); +} + +void Minimap::mouseExited(gcn::MouseEvent &event) +{ + Window::mouseExited(event); + mTextPopup->hide(); +} + +void Minimap::screenToMap(int &x, int &y) +{ + const gcn::Rectangle a = getChildrenArea(); + x = (x - a.x - mMapOriginX + mWidthProportion) / mWidthProportion; + y = (y - a.y - mMapOriginY + mHeightProportion) / mHeightProportion; +} + +void Minimap::optionChanged(const std::string &name) +{ + if (name == "autoresizeminimaps") + mAutoResize = config.getBoolValue("autoresizeminimaps"); +} diff --git a/src/gui/windows/minimap.h b/src/gui/windows/minimap.h new file mode 100644 index 000000000..decacfec4 --- /dev/null +++ b/src/gui/windows/minimap.h @@ -0,0 +1,89 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_MINIMAP_H +#define GUI_MINIMAP_H + +#include "gui/widgets/window.h" + +class Image; +class Map; +class TextPopup; + +/** + * Minimap window. Shows a minimap image and the name of the current map. + * + * The name of the map is defined by the map property "name". The minimap image + * is defined by the map property "minimap". The path to the image should be + * given relative to the root of the client data. + * + * \ingroup Interface + */ +class Minimap final : public Window, public ConfigListener +{ + public: + Minimap(); + + A_DELETE_COPY(Minimap) + + ~Minimap(); + + /** + * Sets the map image that should be displayed. + */ + void setMap(const Map *const map); + + /** + * Toggles the displaying of the minimap. + */ + void toggle(); + + /** + * Draws the minimap. + */ + void draw(gcn::Graphics *graphics) override; + + void mouseMoved(gcn::MouseEvent &event) override; + + void mouseReleased(gcn::MouseEvent &event) override; + + void mouseExited(gcn::MouseEvent &event) override; + + void screenToMap(int &x, int &y); + + void optionChanged(const std::string &name); + + private: + float mWidthProportion; + float mHeightProportion; + Image *mMapImage; + int mMapOriginX; + int mMapOriginY; + TextPopup *mTextPopup; + bool mCustomMapImage; + bool mAutoResize; + static bool mShow; +}; + +extern Minimap *minimap; + +#endif // GUI_MINIMAP_H diff --git a/src/gui/windows/ministatuswindow.cpp b/src/gui/windows/ministatuswindow.cpp new file mode 100644 index 000000000..21697b83f --- /dev/null +++ b/src/gui/windows/ministatuswindow.cpp @@ -0,0 +1,527 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/ministatuswindow.h" + +#include "animatedsprite.h" +#include "configuration.h" + +#include "being/localplayer.h" +#include "being/playerinfo.h" + +#include "gui/statuspopup.h" +#include "gui/textpopup.h" +#include "gui/viewport.h" + +#include "gui/windows/statuswindow.h" + +#include "gui/widgets/progressbar.h" + +#include "net/net.h" +#include "net/playerhandler.h" +#include "net/gamehandler.h" + +#include "utils/dtor.h" +#include "utils/gettext.h" + +#include "debug.h" + +extern volatile int tick_time; + +typedef std::vector ::const_iterator ProgressBarVectorCIter; + +MiniStatusWindow::MiniStatusWindow() : + Popup("MiniStatus", "ministatus.xml"), + InventoryListener(), + mBars(), + mBarNames(), + mIcons(), + mSpacing(mSkin ? mSkin->getOption("spacing", 3) : 3), + mIconPadding(mSkin ? mSkin->getOption("iconPadding", 3) : 3), + mIconSpacing(mSkin ? mSkin->getOption("iconSpacing", 2) : 2), + mMaxX(0), + // TRANSLATORS: status bar name + mHpBar(createBar(0, 100, 0, Theme::PROG_HP, "hp bar", _("health bar"))), + mMpBar(Net::getGameHandler()->canUseMagicBar() + ? createBar(0, 100, 0, Net::getPlayerHandler()->canUseMagic() + // TRANSLATORS: status bar name + ? Theme::PROG_MP : Theme::PROG_NO_MP, "mp bar", _("mana bar")) + : nullptr), + mXpBar(createBar(0, 100, 0, Theme::PROG_EXP, + // TRANSLATORS: status bar name + "xp bar", _("experience bar"))), + mJobBar(nullptr), + mWeightBar(createBar(0, 140, 0, Theme::PROG_WEIGHT, + // TRANSLATORS: status bar name + "weight bar", _("weight bar"))), + mInvSlotsBar(createBar(0, 45, 0, Theme::PROG_INVY_SLOTS, + // TRANSLATORS: status bar name + "inventory slots bar", _("inventory slots bar"))), + mMoneyBar(createBar(0, 130, 0, Theme::PROG_INVY_SLOTS, + // TRANSLATORS: status bar name + "money bar", _("money bar"))), + mArrowsBar(createBar(0, 50, 0, Theme::PROG_INVY_SLOTS, + // TRANSLATORS: status bar name + "arrows bar", _("arrows bar"))), + mStatusBar(createBar(100, (config.getIntValue("fontSize") > 16 + ? 250 : 165), 0, Theme::PROG_EXP, + // TRANSLATORS: status bar name + "status bar", _("status bar"))), + mTextPopup(new TextPopup), + mStatusPopup(new StatusPopup) +{ + listen(CHANNEL_ATTRIBUTES); + + StatusWindow::updateHPBar(mHpBar); + + if (Net::getGameHandler()->canUseMagicBar()) + StatusWindow::updateMPBar(mMpBar); + + const int job = Net::getPlayerHandler()->getJobLocation() + && serverConfig.getValueBool("showJob", true); + + StatusWindow::updateXPBar(mXpBar); + + if (job) + { + mJobBar = createBar(0, 100, 0, Theme::PROG_JOB, "job bar", + // TRANSLATORS: status bar name + _("job bar")); + StatusWindow::updateJobBar(mJobBar); + } + + loadBars(); + updateBars(); + + setVisible(config.getValueBool(getPopupName() + "Visible", true)); + addMouseListener(this); + Inventory *const inv = PlayerInfo::getInventory(); + if (inv) + inv->addInventoyListener(this); + + StatusWindow::updateMoneyBar(mMoneyBar); + StatusWindow::updateArrowsBar(mArrowsBar); + updateStatus(); +} + +MiniStatusWindow::~MiniStatusWindow() +{ + delete mTextPopup; + mTextPopup = nullptr; + delete mStatusPopup; + mStatusPopup = nullptr; + delete_all(mIcons); + mIcons.clear(); + + Inventory *const inv = PlayerInfo::getInventory(); + if (inv) + inv->removeInventoyListener(this); + + FOR_EACH (ProgressBarVectorCIter, it, mBars) + { + ProgressBar *bar = *it; + if (!bar) + continue; + if (!bar->isVisible()) + delete bar; + } + mBars.clear(); +} + +ProgressBar *MiniStatusWindow::createBar(const float progress, + const int width, const int height, + const int color, + const std::string &name, + const std::string &description) +{ + ProgressBar *const bar = new ProgressBar(this, + progress, width, height, color); + bar->setActionEventId(name); + bar->setId(description); + mBars.push_back(bar); + mBarNames[name] = bar; + return bar; +} + +void MiniStatusWindow::updateBars() +{ + int x = 0; + const ProgressBar *lastBar = nullptr; + FOR_EACH (ProgressBarVectorCIter, it, mBars) + safeRemove(*it); + + FOR_EACH (ProgressBarVectorCIter, it, mBars) + { + ProgressBar *const bar = *it; + if (!bar) + continue; + if (bar->isVisible()) + { + bar->setPosition(x, 0); + add(bar); + x += bar->getWidth() + mSpacing; + lastBar = bar; + } + } + + if (lastBar) + { + setContentSize(lastBar->getX() + lastBar->getWidth(), + lastBar->getY() + lastBar->getHeight()); + } + mMaxX = x; +} + +void MiniStatusWindow::setIcon(const int index, AnimatedSprite *const sprite) +{ + if (index >= static_cast(mIcons.size())) + mIcons.resize(index + 1, nullptr); + + delete mIcons[index]; + mIcons[index] = sprite; +} + +void MiniStatusWindow::eraseIcon(const int index) +{ + if (index < static_cast(mIcons.size())) + { + delete mIcons[index]; + mIcons.erase(mIcons.begin() + index); + } +} + +void MiniStatusWindow::drawIcons(Graphics *const graphics) +{ + // Draw icons + int icon_x = mMaxX + mIconPadding; + for (size_t i = 0, sz = mIcons.size(); i < sz; i ++) + { + const AnimatedSprite *const icon = mIcons[i]; + if (icon) + { + icon->draw(graphics, icon_x, mIconPadding); + icon_x += mIconSpacing + icon->getWidth(); + } + } +} + +void MiniStatusWindow::processEvent(const Channels channel A_UNUSED, + const DepricatedEvent &event) +{ + if (event.getName() == EVENT_UPDATEATTRIBUTE) + { + const int id = event.getInt("id"); + if (id == PlayerInfo::HP || id == PlayerInfo::MAX_HP) + { + StatusWindow::updateHPBar(mHpBar); + } + else if (id == PlayerInfo::MP || id == PlayerInfo::MAX_MP) + { + StatusWindow::updateMPBar(mMpBar); + } + else if (id == PlayerInfo::EXP || id == PlayerInfo::EXP_NEEDED) + { + StatusWindow::updateXPBar(mXpBar); + } + else if (id == PlayerInfo::TOTAL_WEIGHT + || id == PlayerInfo::MAX_WEIGHT) + { + StatusWindow::updateWeightBar(mWeightBar); + } + else if (id == PlayerInfo::MONEY) + { + StatusWindow::updateMoneyBar(mMoneyBar); + } + } + else if (event.getName() == EVENT_UPDATESTAT) + { + StatusWindow::updateMPBar(mMpBar); + StatusWindow::updateJobBar(mJobBar); + } +} + +void MiniStatusWindow::updateStatus() +{ + StatusWindow::updateStatusBar(mStatusBar); + if (mStatusPopup && mStatusPopup->isPopupVisible()) + mStatusPopup->update(); +} + +void MiniStatusWindow::logic() +{ + BLOCK_START("MiniStatusWindow::logic") + Popup::logic(); + + for (size_t i = 0, sz = mIcons.size(); i < sz; i++) + { + AnimatedSprite *const icon = mIcons[i]; + if (icon) + icon->update(tick_time * 10); + } + BLOCK_END("MiniStatusWindow::logic") +} + +void MiniStatusWindow::draw(gcn::Graphics *graphics) +{ + BLOCK_START("MiniStatusWindow::draw") + drawChildren(graphics); + BLOCK_END("MiniStatusWindow::draw") +} + +void MiniStatusWindow::mouseMoved(gcn::MouseEvent &event) +{ + Popup::mouseMoved(event); + + const int x = event.getX(); + const int y = event.getY(); + + const gcn::Rectangle &rect = mDimension; + if (event.getSource() == mStatusBar) + { + mStatusPopup->view(x + rect.x, y + rect.y); + mTextPopup->hide(); + } + else if (event.getSource() == mXpBar) + { + std::string level; + if (player_node && player_node->isGM()) + { + // TRANSLATORS: status bar label + level = strprintf(_("Level: %d (GM %d)"), + PlayerInfo::getAttribute(PlayerInfo::LEVEL), + player_node->getGMLevel()); + } + else + { + // TRANSLATORS: status bar label + level = strprintf(_("Level: %d"), + PlayerInfo::getAttribute(PlayerInfo::LEVEL)); + } + + const int exp = PlayerInfo::getAttribute(PlayerInfo::EXP); + const int expNeed = PlayerInfo::getAttribute(PlayerInfo::EXP_NEEDED); + if (exp > expNeed) + { + mTextPopup->show(x + rect.x, y + rect.y, level, strprintf("%d/%d", + exp, expNeed)); + } + else + { + mTextPopup->show(x + rect.x, y + rect.y, level, strprintf("%d/%d", + exp, expNeed), + // TRANSLATORS: status bar label + strprintf("%s: %d", _("Need"), expNeed - exp)); + } + mStatusPopup->hide(); + } + else if (event.getSource() == mHpBar) + { + mTextPopup->show(x + rect.x, y + rect.y, event.getSource()->getId(), + strprintf("%d/%d", PlayerInfo::getAttribute(PlayerInfo::HP), + PlayerInfo::getAttribute(PlayerInfo::MAX_HP))); + mStatusPopup->hide(); + } + else if (event.getSource() == mMpBar) + { + mTextPopup->show(x + rect.x, y + rect.y, event.getSource()->getId(), + strprintf("%d/%d", PlayerInfo::getAttribute(PlayerInfo::MP), + PlayerInfo::getAttribute(PlayerInfo::MAX_MP))); + mStatusPopup->hide(); + } + else if (event.getSource() == mJobBar) + { + const std::pair exp = PlayerInfo::getStatExperience( + Net::getPlayerHandler()->getJobLocation()); + + // TRANSLATORS: job bar label + const std::string level = strprintf(_("Job level: %d"), + PlayerInfo::getStatBase( + Net::getPlayerHandler()->getJobLocation())); + + if (exp.first > exp.second) + { + mTextPopup->show(x + rect.x, y + rect.y, level, + strprintf("%d/%d", exp.first, exp.second)); + } + else + { + mTextPopup->show(x + rect.x, y + rect.y, level, + strprintf("%d/%d", exp.first, exp.second), + // TRANSLATORS: status bar label + strprintf("%s: %d", _("Need"), exp.second - exp.first)); + } + mStatusPopup->hide(); + } + else if (event.getSource() == mWeightBar) + { + mTextPopup->show(x + rect.x, y + rect.y, event.getSource()->getId(), + strprintf("%d/%d", PlayerInfo::getAttribute( + PlayerInfo::TOTAL_WEIGHT), + PlayerInfo::getAttribute(PlayerInfo::MAX_WEIGHT))); + mStatusPopup->hide(); + } + else if (event.getSource() == mInvSlotsBar) + { + const Inventory *const inv = PlayerInfo::getInventory(); + if (inv) + { + const int usedSlots = inv->getNumberOfSlotsUsed(); + const int maxSlots = inv->getSize(); + mTextPopup->show(x + rect.x, y + rect.y, + event.getSource()->getId(), + strprintf("%d/%d", usedSlots, maxSlots)); + } + mStatusPopup->hide(); + } + else if (event.getSource() == mMoneyBar) + { + mTextPopup->show(x + rect.x, y + rect.y, + event.getSource()->getId(), + toString(PlayerInfo::getAttribute(PlayerInfo::MONEY))); + } + else + { + mTextPopup->hide(); + mStatusPopup->hide(); + } +} + +void MiniStatusWindow::mousePressed(gcn::MouseEvent &event) +{ + if (!viewport) + return; + + if (event.getButton() == gcn::MouseEvent::RIGHT) + { + const ProgressBar *const bar = dynamic_cast( + event.getSource()); + if (!bar) + return; + if (viewport) + { + viewport->showPopup(getX() + event.getX(), + getY() + event.getY(), bar); + } + } +} + +void MiniStatusWindow::mouseExited(gcn::MouseEvent &event) +{ + Popup::mouseExited(event); + + mTextPopup->hide(); + mStatusPopup->hide(); +} + +void MiniStatusWindow::showBar(const std::string &name, const bool visible) +{ + ProgressBar *const bar = mBarNames[name]; + if (!bar) + return; + bar->setVisible(visible); + updateBars(); + saveBars(); +} + +void MiniStatusWindow::loadBars() +{ + if (!config.getIntValue("ministatussaved")) + { + if (mWeightBar) + mWeightBar->setVisible(false); + if (mInvSlotsBar) + mInvSlotsBar->setVisible(false); + if (mMoneyBar) + mMoneyBar->setVisible(false); + if (mArrowsBar) + mArrowsBar->setVisible(false); + if (mStatusBar) + mStatusBar->setVisible(false); + if (mJobBar) + mJobBar->setVisible(false); + return; + } + + for (int f = 0; f < 10; f ++) + { + const std::string str = config.getValue( + "ministatus" + toString(f), ""); + if (str == "") + continue; + ProgressBar *const bar = mBarNames[str]; + if (!bar) + continue; + bar->setVisible(false); + } +} + +void MiniStatusWindow::saveBars() const +{ + int i = 0; + FOR_EACH (ProgressBarVectorCIter, it, mBars) + { + const ProgressBar *const bar = *it; + if (!bar->isVisible()) + { + config.setValue("ministatus" + toString(i), + bar->getActionEventId()); + i ++; + } + } + for (int f = i; f < 10; f ++) + config.deleteKey("ministatus" + toString(f)); + + config.setValue("ministatussaved", true); +} + +void MiniStatusWindow::slotsChanged(Inventory *const inventory) +{ + if (!inventory) + return; + + if (inventory->getType() == Inventory::INVENTORY) + StatusWindow::updateInvSlotsBar(mInvSlotsBar); +} + +void MiniStatusWindow::updateArrows() +{ + StatusWindow::updateArrowsBar(mArrowsBar); +} + +gcn::Rectangle MiniStatusWindow::getChildrenArea() +{ + const int padding = mPadding; + const int padding2 = padding * 2; + const gcn::Rectangle &rect = mDimension; + return gcn::Rectangle(padding, padding, + rect.width - padding2, + rect.height - padding2); +} + +#ifdef USE_PROFILER +void MiniStatusWindow::logicChildren() +{ + BLOCK_START("MiniStatusWindow::logicChildren") + BasicContainer::logicChildren(); + BLOCK_END("MiniStatusWindow::logicChildren") +} +#endif diff --git a/src/gui/windows/ministatuswindow.h b/src/gui/windows/ministatuswindow.h new file mode 100644 index 000000000..39d1e689d --- /dev/null +++ b/src/gui/windows/ministatuswindow.h @@ -0,0 +1,135 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_MINISTATUSWINDOW_H +#define GUI_MINISTATUSWINDOW_H + +#include "inventory.h" +#include "depricatedlistener.h" + +#include "gui/widgets/popup.h" + +#include + +class AnimatedSprite; +class Graphics; +class ProgressBar; +class StatusPopup; +class TextPopup; + +/** + * The player mini-status dialog. + * + * \ingroup Interface + */ +class MiniStatusWindow final : public Popup, + public InventoryListener, + public DepricatedListener +{ + public: + MiniStatusWindow(); + + A_DELETE_COPY(MiniStatusWindow) + + ~MiniStatusWindow(); + + /** + * Sets one of the icons. + */ + void setIcon(const int index, AnimatedSprite *const sprite); + + void eraseIcon(const int index); + + void drawIcons(Graphics *const graphics); + + void processEvent(const Channels channel, + const DepricatedEvent &event) override; + + void updateStatus(); + + void logic() override; + + void draw(gcn::Graphics *graphics) override; + + void mouseMoved(gcn::MouseEvent &mouseEvent) override; + + void mousePressed(gcn::MouseEvent &event) override; + + void mouseExited(gcn::MouseEvent &event) override; + + void showBar(const std::string &name, const bool visible); + + void updateBars(); + + void updateArrows(); + + void slotsChanged(Inventory *const inventory) override; + + std::vector &getBars() A_WARN_UNUSED + { return mBars; } + + gcn::Rectangle getChildrenArea() override A_WARN_UNUSED; + +#ifdef USE_PROFILER + void logicChildren(); +#endif + + private: + bool isInBar(ProgressBar *bar, int x, int y) const; + + ProgressBar *createBar(const float progress, const int width, + const int height, const int color, + const std::string &name, + const std::string &description) A_WARN_UNUSED; + + void loadBars(); + + void saveBars() const; + + std::vector mBars; + std::map mBarNames; + std::vector mIcons; + + int mSpacing; + int mIconPadding; + int mIconSpacing; + int mMaxX; + + /* + * Mini Status Bars + */ + ProgressBar *mHpBar; + ProgressBar *mMpBar; + ProgressBar *mXpBar; + ProgressBar *mJobBar; + ProgressBar *mWeightBar; + ProgressBar *mInvSlotsBar; + ProgressBar *mMoneyBar; + ProgressBar *mArrowsBar; + ProgressBar *mStatusBar; + TextPopup *mTextPopup; + StatusPopup *mStatusPopup; +}; + +extern MiniStatusWindow *miniStatusWindow; + +#endif // GUI_MINISTATUSWINDOW_H diff --git a/src/gui/windows/npcdialog.cpp b/src/gui/windows/npcdialog.cpp new file mode 100644 index 000000000..6e546ef61 --- /dev/null +++ b/src/gui/windows/npcdialog.cpp @@ -0,0 +1,961 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/npcdialog.h" + +#include "actorspritemanager.h" +#include "configuration.h" +#include "client.h" +#include "inventory.h" +#include "item.h" +#include "soundconsts.h" +#include "soundmanager.h" + +#include "being/being.h" + +#include "gui/gui.h" +#include "gui/sdlfont.h" +#include "gui/viewport.h" + +#include "gui/windows/inventorywindow.h" + +#include "gui/widgets/browserbox.h" +#include "gui/widgets/button.h" +#include "gui/widgets/inttextfield.h" +#include "gui/widgets/itemcontainer.h" +#include "gui/widgets/itemlinkhandler.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/extendedlistbox.h" +#include "gui/widgets/playerbox.h" +#include "gui/widgets/scrollarea.h" + +#include "resources/avatardb.h" +#include "resources/npcdb.h" +#include "resources/resourcemanager.h" + +#include "net/net.h" +#include "net/npchandler.h" + +#include "utils/copynpaste.h" +#include "utils/gettext.h" + +#include + +#include "debug.h" + +// TRANSLATORS: npc dialog button +#define CAPTION_WAITING _("Stop waiting") +// TRANSLATORS: npc dialog button +#define CAPTION_NEXT _("Next") +// TRANSLATORS: npc dialog button +#define CAPTION_CLOSE _("Close") +// TRANSLATORS: npc dialog button +#define CAPTION_SUBMIT _("Submit") + +NpcDialog::DialogList NpcDialog::instances; +NpcDialogs NpcDialog::mNpcDialogs; + +typedef std::vector::iterator ImageVectorIter; + +NpcDialog::NpcDialog(const int npcId) : + // TRANSLATORS: npc dialog name + Window(_("NPC"), false, nullptr, "npc.xml"), + gcn::ActionListener(), + mNpcId(npcId), + mDefaultInt(0), + mDefaultString(), + mTextBox(new BrowserBox(this, BrowserBox::AUTO_WRAP)), + mScrollArea(new ScrollArea(mTextBox, + getOptionBool("showtextbackground"), "npc_textbackground.xml")), + mText(), + mNewText(), + mItemList(new ExtendedListBox(this, this, "extendedlistbox.xml")), + mListScrollArea(new ScrollArea(mItemList, + getOptionBool("showlistbackground"), "npc_listbackground.xml")), + mItems(), + mImages(), + mItemLinkHandler(new ItemLinkHandler), + mTextField(new TextField(this, "")), + mIntField(new IntTextField(this)), + // TRANSLATORS: npc dialog button + mPlusButton(new Button(this, _("+"), "inc", this)), + // TRANSLATORS: npc dialog button + mMinusButton(new Button(this, _("-"), "dec", this)), + // TRANSLATORS: npc dialog button + mClearButton(new Button(this, _("Clear"), "clear", this)), + mButton(new Button(this, "", "ok", this)), + // TRANSLATORS: npc dialog button + mButton2(new Button(this, _("Close"), "close", this)), + // TRANSLATORS: npc dialog button + mButton3(new Button(this, _("Add"), "add", this)), + // TRANSLATORS: npc dialog button + mResetButton(new Button(this, _("Reset"), "reset", this)), + mInventory(new Inventory(Inventory::NPC, 1)), + mItemContainer(new ItemContainer(this, mInventory)), + mItemScrollArea(new ScrollArea(mItemContainer, + getOptionBool("showitemsbackground"), "npc_listbackground.xml")), + mInputState(NPC_INPUT_NONE), + mActionState(NPC_ACTION_WAIT), + mLastNextTime(0), + mCameraMode(-1), + mCameraX(0), + mCameraY(0), + mPlayerBox(new PlayerBox(nullptr)), + mAvatarBeing(nullptr), + mShowAvatar(false), + mLogInteraction(config.getBoolValue("logNpcInGui")) +{ + // Basic Window Setup + setWindowName("NpcText"); + setResizable(true); + setFocusable(true); + setStickyButtonLock(true); + + setMinWidth(200); + setMinHeight(150); + + setDefaultSize(300, 578, ImageRect::LOWER_LEFT); + + mPlayerBox->setWidth(70); + mPlayerBox->setHeight(100); + + // Setup output text box + mTextBox->setOpaque(false); + mTextBox->setMaxRow(config.getIntValue("ChatLogLength")); + mTextBox->setLinkHandler(mItemLinkHandler); + mTextBox->setFont(gui->getNpcFont()); + mTextBox->setEnableKeys(true); + mTextBox->setEnableTabs(true); + + mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mScrollArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); + + // Setup listbox + mItemList->setWrappingEnabled(true); + mItemList->setActionEventId("ok"); + mItemList->addActionListener(this); + mItemList->setDistributeMousePressed(false); + mItemList->setFont(gui->getNpcFont()); + if (gui->getNpcFont()->getHeight() < 20) + mItemList->setRowHeight(20); + else + mItemList->setRowHeight(gui->getNpcFont()->getHeight()); + + setContentSize(260, 175); + mListScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mItemScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mItemList->setVisible(true); + mTextField->setVisible(true); + mIntField->setVisible(true); + + const gcn::Font *const fnt = mButton->getFont(); + int width = std::max(fnt->getWidth(CAPTION_WAITING), + fnt->getWidth(CAPTION_NEXT)); + width = std::max(width, fnt->getWidth(CAPTION_CLOSE)); + width = std::max(width, fnt->getWidth(CAPTION_SUBMIT)); + mButton->setWidth(8 + width); + + // Place widgets + buildLayout(); + + center(); + loadWindowState(); + + instances.push_back(this); + setVisible(true); + requestFocus(); + enableVisibleSound(true); + soundManager.playGuiSound(SOUND_SHOW_WINDOW); + + if (actorSpriteManager) + { + const Being *const being = actorSpriteManager->findBeing(mNpcId); + if (being) + { + showAvatar(NPCDB::getAvatarFor(being->getSubType())); + setCaption(being->getName()); + } + } + + config.addListener("logNpcInGui", this); +} + +NpcDialog::~NpcDialog() +{ + config.removeListeners(this); + clearLayout(); + + if (mPlayerBox) + { + delete mPlayerBox->getBeing(); + delete mPlayerBox; + } + + delete mTextBox; + mTextBox = nullptr; + delete mClearButton; + mClearButton = nullptr; + delete mButton; + mButton = nullptr; + delete mButton2; + mButton2 = nullptr; + delete mButton3; + mButton3 = nullptr; + + // These might not actually be in the layout, so lets be safe + delete mScrollArea; + mScrollArea = nullptr; + delete mItemList; + mItemList = nullptr; + delete mTextField; + mTextField = nullptr; + delete mIntField; + mIntField = nullptr; + delete mResetButton; + mResetButton = nullptr; + delete mPlusButton; + mPlusButton = nullptr; + delete mMinusButton; + mMinusButton = nullptr; + delete mItemLinkHandler; + mItemLinkHandler = nullptr; + + delete mItemContainer; + mItemContainer = nullptr; + delete mInventory; + mInventory = nullptr; + delete mItemScrollArea; + mItemScrollArea = nullptr; + + delete mListScrollArea; + mListScrollArea = nullptr; + + FOR_EACH (ImageVectorIter, it, mImages) + { + if (*it) + (*it)->decRef(); + } + + mImages.clear(); + + instances.remove(this); +} + +void NpcDialog::addText(const std::string &text, const bool save) +{ + if (save || mLogInteraction) + { + if (mText.size() > 5000) + mText.clear(); + + mNewText.append(text); + mTextBox->addRow(text); + } + mScrollArea->setVerticalScrollAmount(mScrollArea->getVerticalMaxScroll()); + mActionState = NPC_ACTION_WAIT; + buildLayout(); +} + +void NpcDialog::showNextButton() +{ + mActionState = NPC_ACTION_NEXT; + buildLayout(); +} + +void NpcDialog::showCloseButton() +{ + mActionState = NPC_ACTION_CLOSE; + buildLayout(); +} + +void NpcDialog::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "ok") + { + if (mActionState == NPC_ACTION_NEXT) + { + if (!client->limitPackets(PACKET_NPC_NEXT)) + return; + + nextDialog(); + addText(std::string(), false); + } + else if (mActionState == NPC_ACTION_CLOSE + || mActionState == NPC_ACTION_WAIT) + { + closeDialog(); + } + else if (mActionState == NPC_ACTION_INPUT) + { + std::string printText; // Text that will get printed + // in the textbox + switch (mInputState) + { + case NPC_INPUT_LIST: + { + if (gui) + gui->resetClickCount(); + const int selectedIndex = mItemList->getSelected(); + + if (selectedIndex >= static_cast(mItems.size()) + || selectedIndex < 0 + || !client->limitPackets(PACKET_NPC_INPUT)) + { + return; + } + unsigned char choice = static_cast( + selectedIndex + 1); + printText = mItems[selectedIndex]; + + Net::getNpcHandler()->listInput(mNpcId, choice); + break; + } + case NPC_INPUT_STRING: + { + if (!client->limitPackets(PACKET_NPC_INPUT)) + return; + printText = mTextField->getText(); + Net::getNpcHandler()->stringInput(mNpcId, printText); + break; + } + case NPC_INPUT_INTEGER: + { + if (!client->limitPackets(PACKET_NPC_INPUT)) + return; + printText = strprintf("%d", mIntField->getValue()); + Net::getNpcHandler()->integerInput( + mNpcId, mIntField->getValue()); + break; + } + case NPC_INPUT_ITEM: + { + if (!client->limitPackets(PACKET_NPC_INPUT)) + return; + + const Item *const item = mInventory->getItem(0); + std::string str; + if (item) + { + str = strprintf("%d,%d", item->getId(), + item->getColor()); + } + else + { + str = "0,0"; + } + + // need send selected item + Net::getNpcHandler()->stringInput(mNpcId, str); + mInventory->clear(); + break; + } + + case NPC_INPUT_NONE: + default: + break; + } + if (mInputState != NPC_INPUT_ITEM) + { + // addText will auto remove the input layout + addText(strprintf("> \"%s\"", printText.c_str()), false); + } + mNewText.clear(); + } + + if (!mLogInteraction) + mTextBox->clearRows(); + } + else if (eventId == "reset") + { + switch (mInputState) + { + case NPC_INPUT_STRING: + mTextField->setText(mDefaultString); + break; + case NPC_INPUT_INTEGER: + mIntField->setValue(mDefaultInt); + break; + case NPC_INPUT_ITEM: + mInventory->clear(); + break; + case NPC_INPUT_NONE: + case NPC_INPUT_LIST: + default: + break; + } + } + else if (eventId == "inc") + { + mIntField->setValue(mIntField->getValue() + 1); + } + else if (eventId == "dec") + { + mIntField->setValue(mIntField->getValue() - 1); + } + else if (eventId == "clear") + { + switch (mInputState) + { + case NPC_INPUT_ITEM: + mInventory->clear(); + break; + case NPC_INPUT_STRING: + case NPC_INPUT_INTEGER: + case NPC_INPUT_LIST: + case NPC_INPUT_NONE: + default: + clearRows(); + break; + } + } + else if (eventId == "close") + { + if (mActionState == NPC_ACTION_INPUT) + { + switch (mInputState) + { + case NPC_INPUT_ITEM: + Net::getNpcHandler()->stringInput(mNpcId, "0,0"); + break; + case NPC_INPUT_STRING: + case NPC_INPUT_INTEGER: + case NPC_INPUT_NONE: + case NPC_INPUT_LIST: + default: + Net::getNpcHandler()->listInput(mNpcId, 255); + break; + } + closeDialog(); + } + } + else if (eventId == "add") + { + if (inventoryWindow) + { + const Item *const item = inventoryWindow->getSelectedItem(); + if (item) + mInventory->addItem(item->getId(), 1, 1, item->getColor()); + } + } +} + +void NpcDialog::nextDialog() +{ + Net::getNpcHandler()->nextDialog(mNpcId); +} + +void NpcDialog::closeDialog() +{ + restoreCamera(); + Net::getNpcHandler()->closeDialog(mNpcId); +} + +int NpcDialog::getNumberOfElements() +{ + return static_cast(mItems.size()); +} + +std::string NpcDialog::getElementAt(int i) +{ + return mItems[i]; +} + +const Image *NpcDialog::getImageAt(int i) +{ + return mImages[i]; +} + +void NpcDialog::choiceRequest() +{ + mItems.clear(); + FOR_EACH (ImageVectorIter, it, mImages) + { + if (*it) + (*it)->decRef(); + } + mImages.clear(); + mActionState = NPC_ACTION_INPUT; + mInputState = NPC_INPUT_LIST; + buildLayout(); +} + +void NpcDialog::addChoice(const std::string &choice) +{ + mItems.push_back(choice); + mImages.push_back(nullptr); +} + +void NpcDialog::parseListItems(const std::string &itemString) +{ + std::istringstream iss(itemString); + ResourceManager *const resman = ResourceManager::getInstance(); + + std::string tmp; + const std::string path = paths.getStringValue("guiIcons"); + while (getline(iss, tmp, ':')) + { + const size_t pos = tmp.find("|"); + if (pos == std::string::npos) + { + mItems.push_back(tmp); + mImages.push_back(nullptr); + } + else + { + mItems.push_back(tmp.substr(pos + 1)); + Image *const img = resman->getImage(std::string( + path).append(tmp.substr(0, pos)).append(".png")); + mImages.push_back(img); + } + } + + if (!mItems.empty()) + { + mItemList->setSelected(0); + mItemList->requestFocus(); + } + else + { + mItemList->setSelected(-1); + } +} + +void NpcDialog::refocus() +{ + if (!mItems.empty()) + mItemList->refocus(); +} + +void NpcDialog::textRequest(const std::string &defaultText) +{ + mActionState = NPC_ACTION_INPUT; + mInputState = NPC_INPUT_STRING; + mDefaultString = defaultText; + mTextField->setText(defaultText); + + buildLayout(); +} + +bool NpcDialog::isTextInputFocused() const +{ + return mTextField->isFocused(); +} + +bool NpcDialog::isInputFocused() const +{ + return mTextField->isFocused() || mIntField->isFocused() + || mItemList->isFocused(); +} + +bool NpcDialog::isAnyInputFocused() +{ + FOR_EACH (DialogList::const_iterator, it, instances) + { + if ((*it) && (*it)->isInputFocused()) + return true; + } + + return false; +} + +void NpcDialog::integerRequest(const int defaultValue, const int min, + const int max) +{ + mActionState = NPC_ACTION_INPUT; + mInputState = NPC_INPUT_INTEGER; + mDefaultInt = defaultValue; + mIntField->setRange(min, max); + mIntField->setValue(defaultValue); + buildLayout(); +} + +void NpcDialog::itemRequest() +{ + mActionState = NPC_ACTION_INPUT; + mInputState = NPC_INPUT_ITEM; + + buildLayout(); +} + +void NpcDialog::move(const int amount) +{ + if (mActionState != NPC_ACTION_INPUT) + return; + + switch (mInputState) + { + case NPC_INPUT_INTEGER: + mIntField->setValue(mIntField->getValue() + amount); + break; + case NPC_INPUT_LIST: + mItemList->setSelected(mItemList->getSelected() - amount); + break; + case NPC_INPUT_NONE: + case NPC_INPUT_STRING: + case NPC_INPUT_ITEM: + default: + break; + } +} + +void NpcDialog::setVisible(bool visible) +{ + Window::setVisible(visible); + + if (!visible) + scheduleDelete(); +} + +void NpcDialog::optionChanged(const std::string &name) +{ + if (name == "logNpcInGui") + mLogInteraction = config.getBoolValue("logNpcInGui"); +} + +NpcDialog *NpcDialog::getActive() +{ + if (instances.size() == 1) + return instances.front(); + + FOR_EACH (DialogList::const_iterator, it, instances) + { + if ((*it) && (*it)->isFocused()) + return (*it); + } + + return nullptr; +} + +void NpcDialog::closeAll() +{ + FOR_EACH (DialogList::const_iterator, it, instances) + { + if (*it) + (*it)->close(); + } +} + +void NpcDialog::placeNormalControls() +{ + if (mShowAvatar) + { + place(0, 0, mPlayerBox); + place(1, 0, mScrollArea, 5, 3); + place(4, 3, mClearButton); + place(5, 3, mButton); + } + else + { + place(0, 0, mScrollArea, 5, 3); + place(3, 3, mClearButton); + place(4, 3, mButton); + } +} + +void NpcDialog::placeMenuControls() +{ + if (mShowAvatar) + { + place(0, 0, mPlayerBox); + place(1, 0, mScrollArea, 6, 3); + place(0, 3, mListScrollArea, 7, 3); + place(1, 6, mButton2, 2); + place(3, 6, mClearButton, 2); + place(5, 6, mButton, 2); + } + else + { + place(0, 0, mScrollArea, 6, 3); + place(0, 3, mListScrollArea, 6, 3); + place(0, 6, mButton2, 2); + place(2, 6, mClearButton, 2); + place(4, 6, mButton, 2); + } +} + +void NpcDialog::placeTextInputControls() +{ + if (mShowAvatar) + { + place(0, 0, mPlayerBox); + place(1, 0, mScrollArea, 6, 3); + place(0, 3, mTextField, 6); + place(0, 4, mResetButton, 2); + place(4, 4, mClearButton, 2); + place(5, 4, mButton, 2); + } + else + { + place(0, 0, mScrollArea, 6, 3); + place(0, 3, mTextField, 6); + place(0, 4, mResetButton, 2); + place(2, 4, mClearButton, 2); + place(4, 4, mButton, 2); + } +} + +void NpcDialog::placeIntInputControls() +{ + if (mShowAvatar) + { + place(0, 0, mPlayerBox); + place(1, 0, mScrollArea, 6, 3); + place(1, 3, mMinusButton, 1); + place(2, 3, mIntField, 4); + place(6, 3, mPlusButton, 1); + place(0, 4, mResetButton, 2); + place(3, 4, mClearButton, 2); + place(5, 4, mButton, 2); + } + else + { + place(0, 0, mScrollArea, 6, 3); + place(0, 3, mMinusButton, 1); + place(1, 3, mIntField, 4); + place(5, 3, mPlusButton, 1); + place(0, 4, mResetButton, 2); + place(2, 4, mClearButton, 2); + place(4, 4, mButton, 2); + } +} + +void NpcDialog::placeItemInputControls() +{ + if (mShowAvatar) + { + place(0, 0, mPlayerBox); + place(1, 0, mScrollArea, 6, 3); + place(0, 3, mItemScrollArea, 7, 3); + place(1, 6, mButton3, 2); + place(3, 6, mClearButton, 2); + place(5, 6, mButton, 2); + } + else + { + place(0, 0, mScrollArea, 6, 3); + place(0, 3, mItemScrollArea, 6, 3); + place(0, 6, mButton3, 2); + place(2, 6, mClearButton, 2); + place(4, 6, mButton, 2); + } +} + +void NpcDialog::buildLayout() +{ + clearLayout(); + + if (mActionState != NPC_ACTION_INPUT) + { + if (mActionState == NPC_ACTION_WAIT) + mButton->setCaption(CAPTION_WAITING); + else if (mActionState == NPC_ACTION_NEXT) + mButton->setCaption(CAPTION_NEXT); + else if (mActionState == NPC_ACTION_CLOSE) + mButton->setCaption(CAPTION_CLOSE); + placeNormalControls(); + } + else if (mInputState != NPC_INPUT_NONE) + { + mButton->setCaption(CAPTION_SUBMIT); + switch (mInputState) + { + case NPC_INPUT_LIST: + placeMenuControls(); + mItemList->setSelected(-1); + break; + + case NPC_INPUT_STRING: + placeTextInputControls(); + break; + + case NPC_INPUT_INTEGER: + placeIntInputControls(); + break; + + case NPC_INPUT_ITEM: + placeItemInputControls(); + break; + + case NPC_INPUT_NONE: + default: + break; + } + } + + Layout &layout = getLayout(); + layout.setRowHeight(1, Layout::AUTO_SET); + redraw(); + mScrollArea->setVerticalScrollAmount(mScrollArea->getVerticalMaxScroll()); +} + +void NpcDialog::saveCamera() +{ + if (!viewport || mCameraMode >= 0) + return; + + mCameraMode = viewport->getCameraMode(); + mCameraX = viewport->getCameraRelativeX(); + mCameraY = viewport->getCameraRelativeY(); +} + +void NpcDialog::restoreCamera() +{ + if (!viewport || mCameraMode == -1) + return; + + if (!mCameraMode) + { + if (viewport->getCameraMode() != mCameraMode) + viewport->toggleCameraMode(); + } + else + { + if (viewport->getCameraMode() != mCameraMode) + viewport->toggleCameraMode(); + viewport->setCameraRelativeX(mCameraX); + viewport->setCameraRelativeY(mCameraY); + } + mCameraMode = -1; +} + +void NpcDialog::showAvatar(const uint16_t avatarId) +{ + const bool needShow = (avatarId != 0); + if (needShow) + { + delete mAvatarBeing; + mAvatarBeing = new Being(0, ActorSprite::AVATAR, avatarId, nullptr); + mPlayerBox->setPlayer(mAvatarBeing); + if (!mAvatarBeing->empty()) + { + mAvatarBeing->logic(); + const BeingInfo *const info = AvatarDB::get(avatarId); + const int pad2 = 2 * mPadding; + int width = 0; + if (info) + { + width = info->getWidth(); + mPlayerBox->setWidth(width + pad2); + mPlayerBox->setHeight(info->getHeight() + pad2); + } + const Sprite *const sprite = mAvatarBeing->getSprite(0); + if (sprite && !width) + { + mPlayerBox->setWidth(sprite->getWidth() + pad2); + mPlayerBox->setHeight(sprite->getHeight() + pad2); + } + } + } + else + { + delete mAvatarBeing; + mAvatarBeing = nullptr; + mPlayerBox->setPlayer(nullptr); + } + if (needShow != mShowAvatar) + { + mShowAvatar = needShow; + buildLayout(); + } + else + { + mShowAvatar = needShow; + } +} + +void NpcDialog::setAvatarDirection(const uint8_t direction) +{ + Being *const being = mPlayerBox->getBeing(); + if (being) + being->setDirection(direction); +} + +void NpcDialog::setAvatarAction(const int actionId) +{ + Being *const being = mPlayerBox->getBeing(); + if (being) + being->setAction(static_cast(actionId)); +} + +void NpcDialog::logic() +{ + BLOCK_START("NpcDialog::logic") + Window::logic(); + if (mShowAvatar && mAvatarBeing) + { + mAvatarBeing->logic(); + if (mPlayerBox->getWidth() < static_cast(3 * getPadding())) + { + const Sprite *const sprite = mAvatarBeing->getSprite(0); + if (sprite) + { + mPlayerBox->setWidth(sprite->getWidth() + 2 * getPadding()); + mPlayerBox->setHeight(sprite->getHeight() + 2 * getPadding()); + buildLayout(); + } + } + } + BLOCK_END("NpcDialog::logic") +} + +void NpcDialog::clearRows() +{ + mTextBox->clearRows(); +} + +void NpcDialog::clearDialogs() +{ + NpcDialogs::iterator it = mNpcDialogs.begin(); + const NpcDialogs::iterator it_end = mNpcDialogs.end(); + while (it != it_end) + { + delete (*it).second; + ++ it; + } + mNpcDialogs.clear(); +} + +void NpcDialog::mousePressed(gcn::MouseEvent &event) +{ + Window::mousePressed(event); + if (event.getButton() == gcn::MouseEvent::RIGHT + && event.getSource() == mTextBox) + { + if (viewport) + viewport->showNpcDialogPopup(mNpcId); + } +} + +void NpcDialog::copyToClipboard(const int npcId, const int x, const int y) +{ + NpcDialogs::iterator it = mNpcDialogs.find(npcId); + if (it != mNpcDialogs.end()) + { + const BrowserBox *const text = (*it).second->mTextBox; + if (!text) + return; + + std::string str = text->getTextAtPos(x, y); + sendBuffer(str); + } +} diff --git a/src/gui/windows/npcdialog.h b/src/gui/windows/npcdialog.h new file mode 100644 index 000000000..d67407ac9 --- /dev/null +++ b/src/gui/windows/npcdialog.h @@ -0,0 +1,301 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_NPCDIALOG_H +#define GUI_NPCDIALOG_H + +#include "configlistener.h" + +#include "gui/widgets/extendedlistmodel.h" +#include "gui/widgets/window.h" + +#include "utils/stringvector.h" + +#include + +#include + +class Being; +class Button; +class BrowserBox; +class ExtendedListBox; +class ItemLinkHandler; +class Inventory; +class IntTextField; +class ItemContainer; +class NpcDialog; +class PlayerBox; +class ScrollArea; +class TextBox; +class TextField; + +typedef std::map NpcDialogs; + +/** + * The npc dialog. + * + * \ingroup Interface + */ +class NpcDialog final : public Window, + public gcn::ActionListener, + public ExtendedListModel, + public ConfigListener +{ + public: + /** + * Constructor. + * + * @see Window::Window + */ + explicit NpcDialog(const int npcId); + + A_DELETE_COPY(NpcDialog) + + ~NpcDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + /** + * Sets the text shows in the dialog. + * + * @param string The new text. + */ +// void setText(const std::string &string); + + /** + * Adds the text to the text shows in the dialog. Also adds a newline + * to the end. + * + * @param string The text to add. + */ + void addText(const std::string &string, const bool save = true); + + /** + * When called, the widget will show a "Next" button. + */ + void showNextButton(); + + /** + * When called, the widget will show a "Close" button and will close + * the dialog when clicked. + */ + void showCloseButton(); + + /** + * Notifies the server that client has performed a next action. + */ + void nextDialog(); + + /** + * Notifies the server that the client has performed a close action. + */ + void closeDialog(); + + /** + * Returns the number of items in the choices list. + */ + int getNumberOfElements() override A_WARN_UNUSED; + + /** + * Returns the name of item number i of the choices list. + */ + std::string getElementAt(int i) override A_WARN_UNUSED; + + /** + * Returns the image of item number i of the choices list. + */ + const Image *getImageAt(int i) override A_WARN_UNUSED; + + /** + * Makes this dialog request a choice selection from the user. + */ + void choiceRequest(); + + /** + * Adds a choice to the list box. + */ + void addChoice(const std::string &); + + /** + * Fills the options list for an NPC dialog. + * + * @param itemString A string with the options separated with colons. + */ + void parseListItems(const std::string &itemString); + + /** + * Requests a text string from the user. + */ + void textRequest(const std::string &defaultText = ""); + + bool isInputFocused() const A_WARN_UNUSED; + + bool isTextInputFocused() const A_WARN_UNUSED; + + static bool isAnyInputFocused() A_WARN_UNUSED; + + /** + * Requests a interger from the user. + */ + void integerRequest(const int defaultValue = 0, const int min = 0, + const int max = 2147483647); + + void itemRequest(); + + void move(const int amount); + + void setVisible(bool visible) override; + + void optionChanged(const std::string &name) override; + + /** + * Returns true if any instances exist. + */ + static bool isActive() A_WARN_UNUSED + { return !instances.empty(); } + + /** + * Returns the first active instance. Useful for pushing user + * interaction. + */ + static NpcDialog *getActive() A_WARN_UNUSED; + + /** + * Closes all instances. + */ + static void closeAll(); + + /** + * Closes all instances and destroy also net handler dialogs. + */ + static void destroyAll(); + + void saveCamera(); + + void restoreCamera(); + + void refocus(); + + void showAvatar(const uint16_t avatarId); + + void setAvatarDirection(const uint8_t direction); + + void setAvatarAction(const int actionId); + + void logic() override; + + void clearRows(); + + void mousePressed(gcn::MouseEvent &event); + + static void copyToClipboard(const int npcId, const int x, const int y); + + static NpcDialogs mNpcDialogs; + + static void clearDialogs(); + + private: + typedef std::list DialogList; + static DialogList instances; + + void buildLayout(); + + void placeNormalControls(); + + void placeMenuControls(); + + void placeTextInputControls(); + + void placeIntInputControls(); + + void placeItemInputControls(); + + int mNpcId; + + int mDefaultInt; + std::string mDefaultString; + + // Used for the main input area + BrowserBox *mTextBox; + ScrollArea *mScrollArea; + std::string mText; + std::string mNewText; + + // Used for choice input + ExtendedListBox *mItemList; + ScrollArea *mListScrollArea; + StringVect mItems; + std::vector mImages; + ItemLinkHandler *mItemLinkHandler; + + // Used for string and integer input + TextField *mTextField; + IntTextField *mIntField; + Button *mPlusButton; + Button *mMinusButton; + Button *mClearButton; + + // Used for the button + Button *mButton; + Button *mButton2; + Button *mButton3; + + // Will reset the text and integer input to the provided default + Button *mResetButton; + + Inventory *mInventory; + ItemContainer *mItemContainer; + ScrollArea *mItemScrollArea; + + enum NpcInputState + { + NPC_INPUT_NONE = 0, + NPC_INPUT_LIST, + NPC_INPUT_STRING, + NPC_INPUT_INTEGER, + NPC_INPUT_ITEM + }; + + enum NpcActionState + { + NPC_ACTION_WAIT = 0, + NPC_ACTION_NEXT, + NPC_ACTION_INPUT, + NPC_ACTION_CLOSE + }; + + NpcInputState mInputState; + NpcActionState mActionState; + int mLastNextTime; + int mCameraMode; + int mCameraX; + int mCameraY; + PlayerBox *mPlayerBox; + Being *mAvatarBeing; + bool mShowAvatar; + bool mLogInteraction; +}; + +#endif // GUI_NPCDIALOG_H diff --git a/src/gui/windows/npcpostdialog.cpp b/src/gui/windows/npcpostdialog.cpp new file mode 100644 index 000000000..af42495a9 --- /dev/null +++ b/src/gui/windows/npcpostdialog.cpp @@ -0,0 +1,136 @@ +/* + * The ManaPlus Client + * Copyright (C) 2008-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/npcpostdialog.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/chattab.h" +#include "gui/widgets/label.h" +#include "gui/widgets/textbox.h" +#include "gui/widgets/textfield.h" +#include "gui/widgets/scrollarea.h" + +#include "net/net.h" +#include "net/npchandler.h" + +#include "utils/gettext.h" + +#include "debug.h" + +NpcPostDialog::DialogList NpcPostDialog::instances; + +NpcPostDialog::NpcPostDialog(const int npcId): + // TRANSLATORS: npc post dialog caption + Window(_("NPC"), false, nullptr, "npcpost.xml"), + gcn::ActionListener(), + mNpcId(npcId), + mText(new TextBox(this)), + mSender(new TextField(this)) +{ + setContentSize(400, 180); + + // create text field for receiver + // TRANSLATORS: label in npc post dialog + Label *const senderText = new Label(this, _("To:")); + senderText->setPosition(5, 5); + mSender->setPosition(senderText->getWidth() + 5, 5); + mSender->setWidth(65); + + // create button for sending + // TRANSLATORS: button in npc post dialog + Button *const sendButton = new Button(this, _("Send"), "send", this); + sendButton->setPosition(400 - sendButton->getWidth(), + 170 - sendButton->getHeight()); + // TRANSLATORS: button in npc post dialog + Button *const cancelButton = new Button(this, _("Cancel"), "cancel", this); + cancelButton->setPosition(sendButton->getX() + - (cancelButton->getWidth() + 2), sendButton->getY()); + + // create textfield for letter + mText->setHeight(400 - (mSender->getHeight() + sendButton->getHeight())); + mText->setEditable(true); + + // create scroll box for letter text + ScrollArea *const scrollArea = new ScrollArea(mText); + scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + scrollArea->setDimension(gcn::Rectangle( + 5, mSender->getHeight() + 5, + 380, 140 - (mSender->getHeight() + sendButton->getHeight()))); + + add(senderText); + add(mSender); + add(scrollArea); + add(sendButton); + add(cancelButton); + + setLocationRelativeTo(getParent()); + + instances.push_back(this); + setVisible(true); + enableVisibleSound(true); +} + +NpcPostDialog::~NpcPostDialog() +{ + instances.remove(this); +} + +void NpcPostDialog::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "send") + { + if (mSender->getText().empty() || mText->getText().empty()) + { + if (localChatTab) + { + // TRANSLATORS: npc post message error + localChatTab->chatLog(_("Failed to send as sender or letter " + "invalid.")); + } + } + else + { + Net::getNpcHandler()->sendLetter(mNpcId, mSender->getText(), + mText->getText()); + } + setVisible(false); + } + else if (eventId == "cancel") + { + setVisible(false); + } +} + +void NpcPostDialog::setVisible(bool visible) +{ + Window::setVisible(visible); + + if (!visible) + scheduleDelete(); +} + +void NpcPostDialog::closeAll() +{ + FOR_EACH (DialogList::const_iterator, it, instances) + (*it)->close(); +} diff --git a/src/gui/windows/npcpostdialog.h b/src/gui/windows/npcpostdialog.h new file mode 100644 index 000000000..d9c31d6fd --- /dev/null +++ b/src/gui/windows/npcpostdialog.h @@ -0,0 +1,74 @@ +/* + * The ManaPlus Client + * Copyright (C) 2008-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_NPCPOSTDIALOG_H +#define GUI_NPCPOSTDIALOG_H + +#include "gui/widgets/window.h" + +#include + +class TextBox; +class TextField; + +class NpcPostDialog final : public Window, + public gcn::ActionListener +{ + public: + /** + * Constructor + */ + explicit NpcPostDialog(const int npcId); + + A_DELETE_COPY(NpcPostDialog) + + ~NpcPostDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + void setVisible(bool visible) override; + + /** + * Returns true if any instances exist. + */ + static bool isActive() A_WARN_UNUSED + { return !instances.empty(); } + + /** + * Closes all instances. + */ + static void closeAll(); + + private: + typedef std::list DialogList; + static DialogList instances; + + int mNpcId; + + TextBox *mText; + TextField *mSender; +}; + +#endif // GUI_NPCPOSTDIALOG_H diff --git a/src/gui/windows/okdialog.cpp b/src/gui/windows/okdialog.cpp new file mode 100644 index 000000000..49bf8aa0a --- /dev/null +++ b/src/gui/windows/okdialog.cpp @@ -0,0 +1,89 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/okdialog.h" + +#include "soundconsts.h" +#include "soundmanager.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/textbox.h" + +#include "utils/gettext.h" + +#include + +#include "debug.h" + +OkDialog::OkDialog(const std::string &title, const std::string &msg, + const int soundEvent, const bool modal, + const bool showCenter, Window *const parent, + const int minWidth) : + Window(title, modal, parent, "ok.xml"), + gcn::ActionListener(), + mTextBox(new TextBox(this)) +{ + mTextBox->setEditable(false); + mTextBox->setOpaque(false); + mTextBox->setTextWrapped(msg, minWidth); + + // TRANSLATORS: ok dialog button + Button *const okButton = new Button(this, _("OK"), "ok", this); + + int width = getFont()->getWidth(title); + if (width < mTextBox->getMinWidth()) + width = mTextBox->getMinWidth(); + if (width < okButton->getWidth()) + width = okButton->getWidth(); + + if (mTextBox->getWidth() > width) + width = mTextBox->getWidth(); + if (okButton->getWidth() > width) + width = okButton->getWidth(); + setContentSize(width, mTextBox->getHeight() + okButton->getHeight() + + getOption("buttonPadding", 8)); + mTextBox->setPosition((width - mTextBox->getWidth()) / 2, 0); + okButton->setPosition((width - okButton->getWidth()) / 2, + mTextBox->getHeight() + getOption("buttonPadding", 8)); + + add(mTextBox); + add(okButton); + + if (showCenter) + center(); + else + centerHorisontally(); + setVisible(true); + okButton->requestFocus(); + + if (soundEvent == DIALOG_OK) + soundManager.playGuiSound(SOUND_INFO); + else if (soundEvent == DIALOG_ERROR) + soundManager.playGuiSound(SOUND_ERROR); +} + +void OkDialog::action(const gcn::ActionEvent &event) +{ + setActionEventId(event.getId()); + distributeActionEvent(); + scheduleDelete(); +} diff --git a/src/gui/windows/okdialog.h b/src/gui/windows/okdialog.h new file mode 100644 index 000000000..851590595 --- /dev/null +++ b/src/gui/windows/okdialog.h @@ -0,0 +1,71 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_OKDIALOG_H +#define GUI_OKDIALOG_H + +#include "localconsts.h" + +#include "gui/widgets/window.h" + +#include + +class TextBox; + +enum +{ + DIALOG_OK = 0, + DIALOG_ERROR, + DIALOG_SILENCE +}; + +/** + * An 'Ok' button dialog. + * + * \ingroup GUI + */ +class OkDialog final : public Window, + public gcn::ActionListener +{ + public: + /** + * Constructor. + * + * @see Window::Window + */ + OkDialog(const std::string &title, const std::string &msg, + const int soundEvent = DIALOG_OK, const bool modal = true, + const bool showCenter = true, Window *const parent = nullptr, + const int minWidth = 260); + + A_DELETE_COPY(OkDialog) + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + private: + TextBox *mTextBox; +}; + +#endif // GUI_OKDIALOG_H diff --git a/src/gui/windows/outfitwindow.cpp b/src/gui/windows/outfitwindow.cpp new file mode 100644 index 000000000..38a837872 --- /dev/null +++ b/src/gui/windows/outfitwindow.cpp @@ -0,0 +1,662 @@ +/* + * The ManaPlus Client + * Copyright (C) 2007-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/outfitwindow.h" + +#include "configuration.h" +#include "dragdrop.h" +#include "emoteshortcut.h" +#include "game.h" +#include "inventory.h" +#include "item.h" + +#include "being/playerinfo.h" + +#include "input/inputmanager.h" + +#include "gui/viewport.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/checkbox.h" +#include "gui/widgets/label.h" +#include "gui/widgets/layout.h" + +#include "resources/image.h" + +#include "utils/gettext.h" + +#include "net/inventoryhandler.h" +#include "net/net.h" + +#include + +#include "debug.h" + +float OutfitWindow::mAlpha = 1.0; + +OutfitWindow::OutfitWindow(): + // TRANSLATORS: outfits window name + Window(_("Outfits"), false, nullptr, "outfits.xml"), + gcn::ActionListener(), + // TRANSLATORS: outfits window button + mPreviousButton(new Button(this, _("<"), "previous", this)), + // TRANSLATORS: outfits window button + mNextButton(new Button(this, _(">"), "next", this)), + // TRANSLATORS: outfits window button + mEquipButtom(new Button(this, _("Equip"), "equip", this)), + // TRANSLATORS: outfits window label + mCurrentLabel(new Label(this, strprintf(_("Outfit: %d"), 1))), + // TRANSLATORS: outfits window checkbox + mUnequipCheck(new CheckBox(this, _("Unequip first"), + serverConfig.getValueBool("OutfitUnequip0", true))), + // TRANSLATORS: outfits window checkbox + mAwayOutfitCheck(new CheckBox(this, _("Away outfit"), + serverConfig.getValue("OutfitAwayIndex", OUTFITS_COUNT - 1))), + mCurrentOutfit(0), + // TRANSLATORS: outfits window label + mKeyLabel(new Label(this, strprintf(_("Key: %s"), + keyName(mCurrentOutfit).c_str()))), + mBoxWidth(33), + mBoxHeight(33), + mGridWidth(4), + mGridHeight(4), + mItems(), + mAwayOutfit(0), + mBorderColor(getThemeColor(Theme::BORDER, 64)), + mBackgroundColor(getThemeColor(Theme::BACKGROUND, 32)), + mItemColors(), + mItemClicked(false), + mItemsUnequip() +{ + setWindowName("Outfits"); + setResizable(true); + setCloseButton(true); + setStickyButtonLock(true); + + setDefaultSize(250, 400, 150, 290); + setMinWidth(145); + setMinHeight(220); + + mCurrentLabel->setAlignment(gcn::Graphics::CENTER); + mKeyLabel->setAlignment(gcn::Graphics::CENTER); + + mUnequipCheck->setActionEventId("unequip"); + mUnequipCheck->addActionListener(this); + + mAwayOutfitCheck->setActionEventId("away"); + mAwayOutfitCheck->addActionListener(this); + + place(1, 3, mEquipButtom, 2); + place(0, 4, mKeyLabel, 4); + place(0, 5, mPreviousButton, 1); + place(1, 5, mCurrentLabel, 2); + place(3, 5, mNextButton, 1); + place(0, 6, mUnequipCheck, 4); + place(0, 7, mAwayOutfitCheck, 4); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + layout.setColWidth(4, Layout::CENTER); + + loadWindowState(); + + enableVisibleSound(true); + load(); +} + +OutfitWindow::~OutfitWindow() +{ + save(); +} + +void OutfitWindow::load(const bool oldConfig) +{ + const Configuration *cfg; + if (oldConfig) + cfg = &config; + else + cfg = &serverConfig; + + memset(mItems, -1, sizeof(mItems)); + memset(mItemColors, 1, sizeof(mItemColors)); + + for (unsigned o = 0; o < OUTFITS_COUNT; o++) + { + std::string outfit = cfg->getValue("Outfit" + toString(o), "-1"); + std::string buf; + std::stringstream ss(outfit); + + std::vector tokens; + + while (ss >> buf) + tokens.push_back(atoi(buf.c_str())); + + for (size_t i = 0, sz = tokens.size(); + i < sz && i < OUTFIT_ITEM_COUNT; i++) + { + mItems[o][i] = tokens[i]; + } + + outfit = cfg->getValue("OutfitColor" + toString(o), "1"); + std::stringstream ss2(outfit); + + tokens.clear(); + + std::vector tokens2; + while (ss2 >> buf) + tokens2.push_back(static_cast(atoi(buf.c_str()))); + + for (size_t i = 0, sz = tokens2.size(); + i < sz && i < OUTFIT_ITEM_COUNT; i++) + { + mItemColors[o][i] = tokens2[i]; + } + + mItemsUnequip[o] = cfg->getValueBool("OutfitUnequip" + toString(o), + true); + } + mAwayOutfit = cfg->getValue("OutfitAwayIndex", OUTFITS_COUNT - 1); + if (mAwayOutfit >= static_cast(OUTFITS_COUNT)) + mAwayOutfit = static_cast(OUTFITS_COUNT) - 1; + + if (mAwayOutfitCheck) + mAwayOutfitCheck->setSelected(mAwayOutfit == mCurrentOutfit); +} + +void OutfitWindow::save() const +{ + std::string outfitStr; + std::string outfitColorsStr; + for (unsigned o = 0; o < OUTFITS_COUNT; o++) + { + bool good = false; + for (unsigned i = 0; i < OUTFIT_ITEM_COUNT; i++) + { + const int val = mItems[o][i]; + const int res = val ? val : -1; + if (res != -1) + good = true; + outfitStr.append(toString(res)); + if (i < OUTFIT_ITEM_COUNT - 1) + outfitStr.append(" "); + outfitColorsStr.append(toString(static_cast( + mItemColors[o][i]))); + if (i < OUTFIT_ITEM_COUNT - 1) + outfitColorsStr.append(" "); + } + if (good) + { + serverConfig.setValue("Outfit" + toString(o), outfitStr); + serverConfig.setValue("OutfitColor" + toString(o), + outfitColorsStr); + } + else + { + serverConfig.deleteKey("Outfit" + toString(o)); + serverConfig.deleteKey("OutfitColor" + toString(o)); + } + + if (mItemsUnequip[o]) + { + serverConfig.deleteKey("OutfitUnequip" + toString(o)); + } + else + { + serverConfig.setValue("OutfitUnequip" + toString(o), + mItemsUnequip[o]); + } + outfitStr.clear(); + outfitColorsStr.clear(); + } + serverConfig.setValue("OutfitAwayIndex", mAwayOutfit); +} + +void OutfitWindow::action(const gcn::ActionEvent &event) +{ + const std::string eventId = event.getId(); + if (eventId == "next") + { + next(); + } + else if (eventId == "previous") + { + previous(); + } + else if (eventId == "unequip") + { + if (mCurrentOutfit >= 0 && mCurrentOutfit < static_cast( + OUTFITS_COUNT)) + { + mItemsUnequip[mCurrentOutfit] = mUnequipCheck->isSelected(); + } + } + else if (eventId == "equip") + { + wearOutfit(mCurrentOutfit); + if (Game::instance()) + Game::instance()->setValidSpeed(); + } + else if (eventId == "away") + { + mAwayOutfit = mCurrentOutfit; + if (!mAwayOutfitCheck->isSelected()) + mAwayOutfitCheck->setSelected(true); + } +} + +void OutfitWindow::wearOutfit(const int outfit, const bool unwearEmpty, + const bool select) +{ + bool isEmpty = true; + + if (outfit < 0 || outfit > static_cast(OUTFITS_COUNT)) + return; + + for (unsigned i = 0; i < OUTFIT_ITEM_COUNT; i++) + { + const Item *const item = PlayerInfo::getInventory()->findItem( + mItems[outfit][i], mItemColors[outfit][i]); + if (item && !item->isEquipped() && item->getQuantity()) + { + if (item->isEquipment()) + { + Net::getInventoryHandler()->equipItem(item); + isEmpty = false; + } + } + } + + if ((!isEmpty || unwearEmpty) && outfit < static_cast(OUTFITS_COUNT) + && mItemsUnequip[outfit]) + { + unequipNotInOutfit(outfit); + } + if (select) + { + mCurrentOutfit = outfit; + showCurrentOutfit(); + } +} + +void OutfitWindow::copyOutfit(const int outfit) +{ + copyOutfit(outfit, mCurrentOutfit); +} + +void OutfitWindow::copyOutfit(const int src, const int dst) +{ + if (src < 0 || src > static_cast(OUTFITS_COUNT) + || dst < 0 || dst > static_cast(OUTFITS_COUNT)) + { + return; + } + + for (unsigned int i = 0; i < OUTFIT_ITEM_COUNT; i++) + mItems[dst][i] = mItems[src][i]; +} + +void OutfitWindow::draw(gcn::Graphics *graphics) +{ + BLOCK_START("OutfitWindow::draw") + Window::draw(graphics); + Graphics *const g = static_cast(graphics); + + if (mCurrentOutfit < 0 || mCurrentOutfit + >= static_cast(OUTFITS_COUNT)) + { + return; + } + + for (unsigned int i = 0; i < OUTFIT_ITEM_COUNT; i++) + { + const int itemX = mPadding + ((i % mGridWidth) * mBoxWidth); + const int itemY = mPadding + mTitleBarHeight + + ((i / mGridWidth) * mBoxHeight); + + graphics->setColor(mBorderColor); + graphics->drawRectangle(gcn::Rectangle(itemX, itemY, 32, 32)); + graphics->setColor(mBackgroundColor); + graphics->fillRectangle(gcn::Rectangle(itemX, itemY, 32, 32)); + + if (mItems[mCurrentOutfit][i] < 0) + continue; + + bool foundItem = false; + const Inventory *const inv = PlayerInfo::getInventory(); + if (inv) + { + const Item *const item = inv->findItem(mItems[mCurrentOutfit][i], + mItemColors[mCurrentOutfit][i]); + if (item) + { + // Draw item icon. + const Image *const image = item->getImage(); + if (image) + { + g->drawImage(image, itemX, itemY); + foundItem = true; + } + } + } + if (!foundItem) + { + Image *const image = Item::getImage(mItems[mCurrentOutfit][i], + mItemColors[mCurrentOutfit][i]); + if (image) + { + g->drawImage(image, itemX, itemY); + image->decRef(); + } + } + } + BLOCK_END("OutfitWindow::draw") +} + + +void OutfitWindow::mouseDragged(gcn::MouseEvent &event) +{ + if (event.getButton() == gcn::MouseEvent::LEFT) + { + if (dragDrop.isEmpty() && mItemClicked) + { + if (mCurrentOutfit < 0 || mCurrentOutfit + >= static_cast(OUTFITS_COUNT)) + { + Window::mouseDragged(event); + return; + } + + const int index = getIndexFromGrid(event.getX(), event.getY()); + if (index == -1) + { + Window::mouseDragged(event); + return; + } + const int itemId = mItems[mCurrentOutfit][index]; + const unsigned char itemColor = mItemColors[mCurrentOutfit][index]; + if (itemId < 0) + { + Window::mouseDragged(event); + return; + } + mMoved = false; + event.consume(); + const Inventory *const inv = PlayerInfo::getInventory(); + if (inv) + { + Item *const item = inv->findItem(itemId, itemColor); + if (item) + dragDrop.dragItem(item, DRAGDROP_SOURCE_OUTFIT); + else + dragDrop.clear(); + mItems[mCurrentOutfit][index] = -1; + } + } + } + Window::mouseDragged(event); +} + +void OutfitWindow::mousePressed(gcn::MouseEvent &event) +{ + const int index = getIndexFromGrid(event.getX(), event.getY()); + if (index == -1) + { + if (event.getButton() == gcn::MouseEvent::RIGHT && viewport) + { + viewport->showOutfitsPopup(); + event.consume(); + } + else + { + Window::mousePressed(event); + } + return; + } + mMoved = false; + event.consume(); + + if (mItems[mCurrentOutfit][index] > 0) + { + mItemClicked = true; + } + else + { + if (dragDrop.isSelected()) + { + mItems[mCurrentOutfit][index] = dragDrop.getSelected(); + mItemColors[mCurrentOutfit][index] = dragDrop.getSelectedColor(); + dragDrop.deselect(); + } + } + + Window::mousePressed(event); +} + +void OutfitWindow::mouseReleased(gcn::MouseEvent &event) +{ + if (event.getButton() == gcn::MouseEvent::LEFT) + { + if (mCurrentOutfit < 0 || mCurrentOutfit + >= static_cast(OUTFITS_COUNT)) + { + return; + } + const int index = getIndexFromGrid(event.getX(), event.getY()); + if (index == -1) + { + dragDrop.clear(); + Window::mouseReleased(event); + return; + } + mMoved = false; + event.consume(); + if (!dragDrop.isEmpty()) + { + if (dragDrop.isSourceItemContainer()) + { + mItems[mCurrentOutfit][index] = dragDrop.getItem(); + mItemColors[mCurrentOutfit][index] = dragDrop.getItemColor(); + dragDrop.clear(); + dragDrop.deselect(); + } + } + if (mItemClicked) + mItemClicked = false; + } + Window::mouseReleased(event); +} + +int OutfitWindow::getIndexFromGrid(const int pointX, const int pointY) const +{ + const gcn::Rectangle tRect = gcn::Rectangle(mPadding, mTitleBarHeight, + mGridWidth * mBoxWidth, mGridHeight * mBoxHeight); + if (!tRect.isPointInRect(pointX, pointY)) + return -1; + const int index = (((pointY - mTitleBarHeight) / mBoxHeight) * mGridWidth) + + (pointX - mPadding) / mBoxWidth; + if (index >= static_cast(OUTFIT_ITEM_COUNT) || index < 0) + return -1; + return index; +} + +void OutfitWindow::unequipNotInOutfit(const int outfit) const +{ + // here we think that outfit is correct index + + const Inventory *const inventory = PlayerInfo::getInventory(); + if (!inventory) + return; + + const unsigned int invSize = inventory->getSize(); + for (unsigned i = 0; i < invSize; i++) + { + const Item *const item = inventory->getItem(i); + if (item && item->isEquipped()) + { + bool found = false; + for (unsigned f = 0; f < OUTFIT_ITEM_COUNT; f++) + { + if (item->getId() == mItems[outfit][f]) + { + found = true; + break; + } + } + if (!found) + Net::getInventoryHandler()->unequipItem(item); + } + } +} + +std::string OutfitWindow::keyName(const int number) const +{ + if (number < 0 || number >= SHORTCUT_EMOTES) + return ""; + return inputManager.getKeyStringLong(static_cast( + Input::KEY_EMOTE_1) + number); +} + +void OutfitWindow::next() +{ + if (mCurrentOutfit < (static_cast(OUTFITS_COUNT) - 1)) + mCurrentOutfit++; + else + mCurrentOutfit = 0; + showCurrentOutfit(); +} + +void OutfitWindow::previous() +{ + if (mCurrentOutfit > 0) + mCurrentOutfit--; + else + mCurrentOutfit = OUTFITS_COUNT - 1; + showCurrentOutfit(); +} + +void OutfitWindow::showCurrentOutfit() +{ + // TRANSLATORS: outfits window label + mCurrentLabel->setCaption(strprintf(_("Outfit: %d"), mCurrentOutfit + 1)); + if (mCurrentOutfit < static_cast(OUTFITS_COUNT)) + mUnequipCheck->setSelected(mItemsUnequip[mCurrentOutfit]); + else + mUnequipCheck->setSelected(false); + // TRANSLATORS: outfits window label + mKeyLabel->setCaption(strprintf(_("Key: %s"), + keyName(mCurrentOutfit).c_str())); + mAwayOutfitCheck->setSelected(mAwayOutfit == mCurrentOutfit); +} + +void OutfitWindow::wearNextOutfit(const bool all) +{ + next(); + if (!all && mCurrentOutfit >= 0 && mCurrentOutfit + < static_cast(OUTFITS_COUNT)) + { + bool fromStart = false; + while (!mItemsUnequip[mCurrentOutfit]) + { + next(); + if (mCurrentOutfit == 0) + { + if (!fromStart) + fromStart = true; + else + return; + } + } + } + wearOutfit(mCurrentOutfit); +} + +void OutfitWindow::wearPreviousOutfit(const bool all) +{ + previous(); + if (!all && mCurrentOutfit >= 0 && mCurrentOutfit + < static_cast(OUTFITS_COUNT)) + { + bool fromStart = false; + while (!mItemsUnequip[mCurrentOutfit]) + { + previous(); + if (mCurrentOutfit == 0) + { + if (!fromStart) + fromStart = true; + else + return; + } + } + } + wearOutfit(mCurrentOutfit); +} + +void OutfitWindow::copyFromEquiped() +{ + copyFromEquiped(mCurrentOutfit); +} + +void OutfitWindow::copyFromEquiped(const int dst) +{ + const Inventory *const inventory = PlayerInfo::getInventory(); + if (!inventory) + return; + + int outfitCell = 0; + for (unsigned i = 0, sz = inventory->getSize(); i < sz; i++) + { + const Item *const item = inventory->getItem(i); + if (item && item->isEquipped()) + { + mItems[dst][outfitCell] = item->getId(); + mItemColors[dst][outfitCell++] = item->getColor(); + if (outfitCell >= static_cast(OUTFIT_ITEM_COUNT)) + break; + } + } +} + +void OutfitWindow::wearAwayOutfit() +{ + copyFromEquiped(OUTFITS_COUNT); + wearOutfit(mAwayOutfit, false); +} + +void OutfitWindow::unwearAwayOutfit() +{ + wearOutfit(OUTFITS_COUNT); +} + +void OutfitWindow::clearCurrentOutfit() +{ + if (mCurrentOutfit < 0 || mCurrentOutfit + >= static_cast(OUTFITS_COUNT)) + { + return; + } + for (unsigned f = 0; f < OUTFIT_ITEM_COUNT; f++) + { + mItems[mCurrentOutfit][f] = -1; + mItemColors[mCurrentOutfit][f] = 1; + } +} diff --git a/src/gui/windows/outfitwindow.h b/src/gui/windows/outfitwindow.h new file mode 100644 index 000000000..5f7d32e02 --- /dev/null +++ b/src/gui/windows/outfitwindow.h @@ -0,0 +1,129 @@ +/* + * The ManaPlus Client + * Copyright (C) 2007-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_OUTFITWINDOW_H +#define GUI_OUTFITWINDOW_H + +#include "gui/widgets/window.h" + +#include + +const unsigned int OUTFITS_COUNT = 100; +const unsigned int OUTFIT_ITEM_COUNT = 16; + +class Button; +class CheckBox; +class Label; + +class OutfitWindow final : public Window, + private gcn::ActionListener +{ + public: + /** + * Constructor. + */ + OutfitWindow(); + + A_DELETE_COPY(OutfitWindow) + + /** + * Destructor. + */ + ~OutfitWindow(); + + void action(const gcn::ActionEvent &event) override; + + void draw(gcn::Graphics *graphics) override; + + void mousePressed(gcn::MouseEvent &event) override; + + void mouseDragged(gcn::MouseEvent &event) override; + + void mouseReleased(gcn::MouseEvent &event) override; + + void load(const bool oldConfig = false); + + void wearOutfit(const int outfit, const bool unwearEmpty = true, + const bool select = false); + + void copyOutfit(const int outfit); + + void copyOutfit(const int src, const int dst); + + void copyFromEquiped(); + + void copyFromEquiped(const int dst); + + void unequipNotInOutfit(const int outfit) const; + + void next(); + + void previous(); + + void wearNextOutfit(const bool all = false); + + void wearPreviousOutfit(const bool all = false); + + void wearAwayOutfit(); + + void unwearAwayOutfit(); + + void showCurrentOutfit(); + + std::string keyName(const int number) const A_WARN_UNUSED; + + void clearCurrentOutfit(); + + private: + Button *mPreviousButton; + Button *mNextButton; + Button *mEquipButtom; + Label *mCurrentLabel; + CheckBox *mUnequipCheck; + CheckBox *mAwayOutfitCheck; + int mCurrentOutfit; + Label *mKeyLabel; + + int getIndexFromGrid(const int pointX, + const int pointY) const A_WARN_UNUSED; + void save() const; + + int mBoxWidth; + int mBoxHeight; + int mGridWidth; + int mGridHeight; + + int mItems[OUTFITS_COUNT + 1][OUTFIT_ITEM_COUNT]; + int mAwayOutfit; + + gcn::Color mBorderColor; + gcn::Color mBackgroundColor; + unsigned char mItemColors[OUTFITS_COUNT + 1][OUTFIT_ITEM_COUNT]; + bool mItemClicked; + bool mItemsUnequip[OUTFITS_COUNT]; + + static float mAlpha; +}; + +extern OutfitWindow *outfitWindow; + +#endif // GUI_OUTFITWINDOW_H diff --git a/src/gui/windows/questswindow.cpp b/src/gui/windows/questswindow.cpp new file mode 100644 index 000000000..8baa2454c --- /dev/null +++ b/src/gui/windows/questswindow.cpp @@ -0,0 +1,567 @@ +/* + * The ManaPlus Client + * Copyright (C) 2012-2013 The ManaPlus developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/questswindow.h" + +#include "actorspritemanager.h" +#include "configuration.h" +#include "effectmanager.h" + +#include "being/localplayer.h" + +#include "gui/gui.h" +#include "gui/sdlfont.h" + +#include "gui/widgets/browserbox.h" +#include "gui/widgets/button.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/extendedlistbox.h" +#include "gui/widgets/extendednamesmodel.h" +#include "gui/widgets/itemlinkhandler.h" +#include "gui/widgets/scrollarea.h" + +#include "utils/dtor.h" +#include "utils/gettext.h" + +#include "utils/translation/podict.h" + +#include "debug.h" + +enum QuestType +{ + QUEST_TEXT = 0, + QUEST_NAME = 1, + QUEST_REWARD = 2 +}; + +struct QuestItemText final +{ + QuestItemText(const std::string &text0, const int type0) : + text(text0), type(type0) + { + } + + std::string text; + int type; +}; + +struct QuestItem final +{ + QuestItem() : + var(0), + name(), + group(), + incomplete(), + complete(), + texts(), + completeFlag(-1), + broken(false) + { + } + + int var; + std::string name; + std::string group; + std::set incomplete; + std::set complete; + std::vector texts; + int completeFlag; + bool broken; +}; + +class QuestsModel final : public ExtendedNamesModel +{ + public: + QuestsModel() : + ExtendedNamesModel() + { + } + + A_DELETE_COPY(QuestsModel) + + ~QuestsModel() + { } +}; + +struct QuestEffect final +{ + QuestEffect() : + map(), + var(0), + id(0), + effectId(0), + values() + { + } + + std::string map; + int var; + int id; + int effectId; + std::set values; +}; + +QuestsWindow::QuestsWindow() : + // TRANSLATORS: quests window name + Window(_("Quests"), false, nullptr, "quests.xml"), + gcn::ActionListener(), + mQuestsModel(new QuestsModel), + mQuestsListBox(new ExtendedListBox(this, + mQuestsModel, "extendedlistbox.xml")), + mQuestScrollArea(new ScrollArea(mQuestsListBox, + getOptionBool("showlistbackground"), "quests_list_background.xml")), + mItemLinkHandler(new ItemLinkHandler), + mText(new BrowserBox(this, BrowserBox::AUTO_WRAP)), + mTextScrollArea(new ScrollArea(mText, + getOptionBool("showtextbackground"), "quests_text_background.xml")), + // TRANSLATORS: quests window button + mCloseButton(new Button(this, _("Close"), "close", this)), + mVars(), + mQuests(), + mAllEffects(), + mMapEffects(), + mNpcEffects(), + mQuestLinks(), + mCompleteIcon(Theme::getImageFromThemeXml("complete_icon.xml", "")), + mIncompleteIcon(Theme::getImageFromThemeXml("incomplete_icon.xml", "")), + mNewQuestEffectId(paths.getIntValue("newQuestEffectId")), + mCompleteQuestEffectId(paths.getIntValue("completeQuestEffectId")), + mMap(nullptr) +{ + setWindowName("Quests"); + setResizable(true); + setCloseButton(true); + setStickyButtonLock(true); + setSaveVisible(true); + + setDefaultSize(400, 350, ImageRect::RIGHT); + setMinWidth(310); + setMinHeight(220); + + mQuestsListBox->setActionEventId("select"); + mQuestsListBox->addActionListener(this); + + mQuestScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mText->setOpaque(false); + mText->setLinkHandler(mItemLinkHandler); + mTextScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mQuestsListBox->setWidth(500); + if (gui->getNpcFont()->getHeight() < 20) + mQuestsListBox->setRowHeight(20); + else + mQuestsListBox->setRowHeight(gui->getNpcFont()->getHeight()); + + ContainerPlacer placer; + placer = getPlacer(0, 0); + + placer(0, 0, mQuestScrollArea, 4, 3).setPadding(3); + placer(4, 0, mTextScrollArea, 4, 3).setPadding(3); + placer(7, 3, mCloseButton); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + + loadWindowState(); + enableVisibleSound(true); + loadXml(); +} + +QuestsWindow::~QuestsWindow() +{ + delete mQuestsModel; + mQuestsModel = nullptr; + + for (std::map >::iterator it + = mQuests.begin(), it_end = mQuests.end(); it != it_end; ++ it) + { + std::vector &quests = (*it).second; + for (std::vector::iterator it2 = quests.begin(), + it2_end = quests.end(); it2 != it2_end; ++ it2) + { + delete *it2; + } + } + delete_all(mAllEffects); + mAllEffects.clear(); + + delete mItemLinkHandler; + mItemLinkHandler = nullptr; + mQuests.clear(); + mQuestLinks.clear(); + if (mCompleteIcon) + { + mCompleteIcon->decRef(); + mCompleteIcon = nullptr; + } + if (mIncompleteIcon) + { + mIncompleteIcon->decRef(); + mIncompleteIcon = nullptr; + } +} + +void QuestsWindow::loadXml() +{ + XML::Document doc(paths.getStringValue("questsFile")); + const XmlNodePtr root = doc.rootNode(); + if (!root) + return; + + for_each_xml_child_node(varNode, root) + { + if (xmlNameEqual(varNode, "var")) + { + const int id = XML::getProperty(varNode, "id", 0); + if (id < 0) + continue; + for_each_xml_child_node(questNode, varNode) + { + if (xmlNameEqual(questNode, "quest")) + loadQuest(id, questNode); + else if (xmlNameEqual(questNode, "effect")) + loadEffect(id, questNode); + } + } + } +} + +void QuestsWindow::loadQuest(const int var, const XmlNodePtr node) +{ + QuestItem *const quest = new QuestItem(); + // TRANSLATORS: quests window quest name + quest->name = XML::langProperty(node, "name", _("unknown")); + quest->group = XML::getProperty(node, "group", ""); + std::string incompleteStr = XML::getProperty(node, "incomplete", ""); + std::string completeStr = XML::getProperty(node, "complete", ""); + if (incompleteStr.empty() && completeStr.empty()) + { + logger->log("complete flags incorrect"); + delete quest; + return; + } + splitToIntSet(quest->incomplete, incompleteStr, ','); + splitToIntSet(quest->complete, completeStr, ','); + if (quest->incomplete.empty() && quest->complete.empty()) + { + logger->log("complete flags incorrect"); + delete quest; + return; + } + if (quest->incomplete.empty() || quest->complete.empty()) + quest->broken = true; + + for_each_xml_child_node(dataNode, node) + { + if (!xmlTypeEqual(dataNode, XML_ELEMENT_NODE)) + continue; + const char *const data = reinterpret_cast( + xmlNodeGetContent(dataNode)); + if (!data) + continue; + std::string str = translator->getStr(data); + + if (xmlNameEqual(dataNode, "text")) + quest->texts.push_back(QuestItemText(str, QUEST_TEXT)); + else if (xmlNameEqual(dataNode, "name")) + quest->texts.push_back(QuestItemText(str, QUEST_NAME)); + else if (xmlNameEqual(dataNode, "reward")) + quest->texts.push_back(QuestItemText(str, QUEST_REWARD)); + } + mQuests[var].push_back(quest); +} + +void QuestsWindow::loadEffect(const int var, const XmlNodePtr node) +{ + QuestEffect *const effect = new QuestEffect; + effect->map = XML::getProperty(node, "map", ""); + effect->id = XML::getProperty(node, "npc", -1); + effect->effectId = XML::getProperty(node, "effect", -1); + const std::string values = XML::getProperty(node, "value", ""); + splitToIntSet(effect->values, values, ','); + + if (effect->map.empty() || effect->id == -1 + || effect->effectId == -1 || values.empty()) + { + delete effect; + return; + } + effect->var = var; + mAllEffects.push_back(effect); +} + +void QuestsWindow::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "select") + { + const int id = mQuestsListBox->getSelected(); + if (id < 0) + return; + showQuest(mQuestLinks[id]); + } + else if (eventId == "close") + { + setVisible(false); + } +} + +void QuestsWindow::updateQuest(const int var, const int val) +{ + mVars[var] = val; +} + +void QuestsWindow::rebuild(const bool playSound) +{ + mQuestsModel->clear(); + mQuestLinks.clear(); + StringVect &names = mQuestsModel->getNames(); + std::vector &images = mQuestsModel->getImages(); + std::vector complete; + std::vector incomplete; + std::vector hidden; + int updatedQuest = -1; + int newCompleteStatus = -1; + + for (std::map::const_iterator it = mVars.begin(), + it_end = mVars.end(); it != it_end; ++ it) + { + const int var = (*it).first; + const int val = (*it).second; + const std::vector &quests = mQuests[var]; + FOR_EACH (std::vector::const_iterator, it2, quests) + { + if (!*it2) + continue; + QuestItem *const quest = *it2; + // complete quest + if (quest->complete.find(val) != quest->complete.end()) + complete.push_back(quest); + // incomplete quest + else if (quest->incomplete.find(val) != quest->incomplete.end()) + incomplete.push_back(quest); + // hidden quest + else + hidden.push_back(quest); + } + } + + int k = 0; + + for (std::vector::const_iterator it = complete.begin(), + it_end = complete.end(); it != it_end; ++ it, k ++) + { + QuestItem *const quest = *it; + if (quest->completeFlag == 0 || (quest->broken + && quest->completeFlag == -1)) + { + updatedQuest = k; + newCompleteStatus = 1; + } + quest->completeFlag = 1; + mQuestLinks.push_back(quest); + names.push_back(quest->name); + if (mCompleteIcon) + { + mCompleteIcon->incRef(); + images.push_back(mCompleteIcon); + } + else + { + images.push_back(nullptr); + } + } + + for (std::vector::const_iterator it = incomplete.begin(), + it_end = incomplete.end(); it != it_end; ++ it, k ++) + { + QuestItem *const quest = *it; + if (quest->completeFlag == -1) + { + updatedQuest = k; + newCompleteStatus = 0; + } + quest->completeFlag = 0; + mQuestLinks.push_back(quest); + names.push_back(quest->name); + if (mIncompleteIcon) + { + mIncompleteIcon->incRef(); + images.push_back(mIncompleteIcon); + } + else + { + images.push_back(nullptr); + } + } + + FOR_EACH (std::vector::const_iterator, it, hidden) + (*it)->completeFlag = -1; + + if (updatedQuest == -1 || updatedQuest >= static_cast( + mQuestLinks.size())) + { + updatedQuest = static_cast(mQuestLinks.size() - 1); + } + if (updatedQuest >= 0) + { + mQuestsListBox->setSelected(updatedQuest); + showQuest(mQuestLinks[updatedQuest]); + if (playSound && effectManager) + { + switch (newCompleteStatus) + { + case 0: + effectManager->trigger(mNewQuestEffectId, player_node); + break; + case 1: + effectManager->trigger(mCompleteQuestEffectId, + player_node); + break; + default: + break; + } + } + } + updateEffects(); +} + +void QuestsWindow::showQuest(const QuestItem *const quest) +{ + if (!quest || !translator) + return; + + const std::vector &texts = quest->texts; + mText->clearRows(); + FOR_EACH (std::vector::const_iterator, it, texts) + { + const QuestItemText &data = *it; + switch (data.type) + { + case QUEST_TEXT: + case QUEST_REWARD: + default: + mText->addRow(translator->getStr(data.text)); + break; + case QUEST_NAME: + mText->addRow(std::string("[").append(translator->getStr( + data.text)).append("]")); + break; + } + } +} + +void QuestsWindow::setMap(const Map *const map) +{ + if (mMap != map) + { + mMap = map; + mMapEffects.clear(); + if (!mMap) + return; + + const std::string name = mMap->getProperty("shortName"); + FOR_EACH (std::vector::const_iterator, it, mAllEffects) + { + const QuestEffect *const effect = *it; + if (effect && name == effect->map) + mMapEffects.push_back(effect); + } + updateEffects(); + } +} + +void QuestsWindow::updateEffects() +{ + NpcQuestEffectMap oldNpc = mNpcEffects; + mNpcEffects.clear(); + + FOR_EACH (std::vector::const_iterator, + it, mMapEffects) + { + const QuestEffect *const effect = *it; + if (effect) + { + const std::map::const_iterator + varIt = mVars.find(effect->var); + if (varIt != mVars.end()) + { + const std::set &vals = effect->values; + if (vals.find(mVars[effect->var]) != vals.end()) + mNpcEffects[effect->id] = effect; + } + } + } + if (!actorSpriteManager) + return; + + std::set removeEffects; + std::map addEffects; + + // for old effects + FOR_EACH (NpcQuestEffectMapCIter, it, oldNpc) + { + const int id = (*it).first; + const QuestEffect *const effect = (*it).second; + + const NpcQuestEffectMapCIter itNew = mNpcEffects.find(id); + if (itNew == mNpcEffects.end()) + { // in new list no effect for this npc + removeEffects.insert(id); + } + else + { // in new list exists effect for this npc + const QuestEffect *const newEffect = (*itNew).second; + if (effect != newEffect) + { // new effects is not equal to old effect + addEffects[id] = newEffect->effectId; + removeEffects.insert(id); + } + } + } + + // for new effects + FOR_EACH (NpcQuestEffectMapCIter, it, mNpcEffects) + { + const int id = (*it).first; + const QuestEffect *const effect = (*it).second; + + const NpcQuestEffectMapCIter itNew = oldNpc.find(id); + // check if old effect was not present + if (itNew == oldNpc.end()) + addEffects[id] = effect->effectId; + } + if (!removeEffects.empty() || !addEffects.empty()) + actorSpriteManager->updateEffects(addEffects, removeEffects); +} + +void QuestsWindow::addEffect(Being *const being) +{ + if (!being) + return; + const int id = being->getSubType(); + const std::map::const_iterator + it = mNpcEffects.find(id); + if (it != mNpcEffects.end()) + { + const QuestEffect *const effect = (*it).second; + if (effect) + being->addSpecialEffect(effect->effectId); + } +} diff --git a/src/gui/windows/questswindow.h b/src/gui/windows/questswindow.h new file mode 100644 index 000000000..72fdb7bb6 --- /dev/null +++ b/src/gui/windows/questswindow.h @@ -0,0 +1,106 @@ +/* + * The ManaPlus Client + * Copyright (C) 2012-2013 The ManaPlus developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_QUESTSWINDOW_H +#define GUI_QUESTSWINDOW_H + +#include "localconsts.h" + +#include "gui/widgets/window.h" + +#include "utils/xml.h" + +#include + +#include +#include + +class Being; +class Button; +class BrowserBox; +class ExtendedListBox; +class ItemLinkHandler; +class Map; +class ScrollArea; +class QuestsModel; + +struct QuestEffect; +struct QuestItem; + +typedef std::map NpcQuestEffectMap; +typedef NpcQuestEffectMap::const_iterator NpcQuestEffectMapCIter; + +class QuestsWindow final : public Window, + public gcn::ActionListener +{ + public: + QuestsWindow(); + + A_DELETE_COPY(QuestsWindow) + + ~QuestsWindow(); + + void action(const gcn::ActionEvent &event) override; + + void updateQuest(const int var, const int val); + + void rebuild(const bool playSound); + + void showQuest(const QuestItem *const quest); + + void setMap(const Map *const map); + + void updateEffects(); + + void addEffect(Being *const being); + + private: + void loadXml(); + + void loadQuest(const int var, const XmlNodePtr node); + + void loadEffect(const int var, const XmlNodePtr node); + + QuestsModel *mQuestsModel; + ExtendedListBox *mQuestsListBox; + ScrollArea *mQuestScrollArea; + ItemLinkHandler *mItemLinkHandler; + BrowserBox *mText; + ScrollArea *mTextScrollArea; + Button *mCloseButton; + // quest variables: var, value + std::map mVars; + // quests: var, quests + std::map > mQuests; + std::vector mAllEffects; + std::vector mMapEffects; + // npc effects for current map and values: npc, effect + NpcQuestEffectMap mNpcEffects; + std::vector mQuestLinks; + Image *mCompleteIcon; + Image *mIncompleteIcon; + int mNewQuestEffectId; + int mCompleteQuestEffectId; + const Map *mMap; +}; + +extern QuestsWindow *questsWindow; + +#endif // GUI_QUESTSWINDOW_H diff --git a/src/gui/windows/quitdialog.cpp b/src/gui/windows/quitdialog.cpp new file mode 100644 index 000000000..0eeece318 --- /dev/null +++ b/src/gui/windows/quitdialog.cpp @@ -0,0 +1,256 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/quitdialog.h" + +#include "client.h" +#include "configuration.h" +#include "game.h" +#include "soundconsts.h" +#include "soundmanager.h" + +#include "input/keydata.h" +#include "input/keyevent.h" + +#include "gui/viewport.h" + +#include "gui/widgets/layout.h" +#include "gui/widgets/button.h" +#include "gui/widgets/radiobutton.h" + +#include "net/charserverhandler.h" +#include "net/gamehandler.h" +#include "net/net.h" + +#include "utils/gettext.h" +#include "utils/process.h" + +#include "debug.h" + +QuitDialog::QuitDialog(QuitDialog **const pointerToMe): + // TRANSLATORS: quit dialog name + Window(_("Quit"), true, nullptr, "quit.xml"), + gcn::ActionListener(), + gcn::KeyListener(), + mOptions(), + // TRANSLATORS: quit dialog button + mLogoutQuit(new RadioButton(this, _("Quit"), "quitdialog")), + // TRANSLATORS: quit dialog button + mForceQuit(new RadioButton(this, _("Quit"), "quitdialog")), + mSwitchAccountServer(new RadioButton(this, + // TRANSLATORS: quit dialog button + _("Switch server"), "quitdialog")), + mSwitchCharacter(new RadioButton(this, + // TRANSLATORS: quit dialog button + _("Switch character"), "quitdialog")), + mRate(nullptr), + // TRANSLATORS: quit dialog button + mOkButton(new Button(this, _("OK"), "ok", this)), + // TRANSLATORS: quit dialog button + mCancelButton(new Button(this, _("Cancel"), "cancel", this)), + mMyPointer(pointerToMe), + mNeedForceQuit(false) +{ + addKeyListener(this); + + ContainerPlacer placer = getPlacer(0, 0); + const State state = client->getState(); + mNeedForceQuit = (state == STATE_CHOOSE_SERVER + || state == STATE_CONNECT_SERVER || state == STATE_LOGIN + || state == STATE_PRE_LOGIN || state == STATE_LOGIN_ATTEMPT + || state == STATE_UPDATE || state == STATE_LOAD_DATA); + + // All states, when we're not logged in to someone. + if (mNeedForceQuit) + { + placeOption(placer, mForceQuit); + } + else + { + // Only added if we are connected to an accountserver or gameserver + placeOption(placer, mLogoutQuit); + placeOption(placer, mSwitchAccountServer); + + // Only added if we are connected to a gameserver + if (state == STATE_GAME) + placeOption(placer, mSwitchCharacter); + } + +/* +#ifdef ANDROID + if (config.getBoolValue("rated") == false + && config.getIntValue("gamecount") > 3) + { + mRate = new RadioButton(this, _("Rate in google play"), "quitdialog"); + placeOption(placer, mRate); + mOptions[mOptions.size() - 1]->setSelected(true); + } + else +#endif +*/ + { + mOptions[0]->setSelected(true); + } + + placer = getPlacer(0, 1); + placer(1, 0, mOkButton, 1); + placer(2, 0, mCancelButton, 1); + + reflowLayout(200, 0); + setLocationRelativeTo(getParent()); + setVisible(true); + soundManager.playGuiSound(SOUND_SHOW_WINDOW); + requestModalFocus(); + mOkButton->requestFocus(); +} + +QuitDialog::~QuitDialog() +{ + if (mMyPointer) + *mMyPointer = nullptr; + delete mForceQuit; + mForceQuit = nullptr; + delete mLogoutQuit; + mLogoutQuit = nullptr; + delete mSwitchAccountServer; + mSwitchAccountServer = nullptr; + delete mSwitchCharacter; + mSwitchCharacter = nullptr; +} + +void QuitDialog::placeOption(ContainerPlacer &placer, + RadioButton *const option) +{ + placer(0, static_cast(mOptions.size()), option, 3); + mOptions.push_back(option); +} + +void QuitDialog::action(const gcn::ActionEvent &event) +{ + soundManager.playGuiSound(SOUND_HIDE_WINDOW); + if (event.getId() == "ok") + { + if (viewport) + { + const Map *const map = viewport->getMap(); + if (map) + map->saveExtraLayer(); + } + + if (mForceQuit->isSelected()) + { + client->setState(STATE_FORCE_QUIT); + } + else if (mLogoutQuit->isSelected()) + { + Game::closeDialogs(); + client->setState(STATE_EXIT); + } + else if (mRate && mRate->isSelected()) + { + openBrowser("https://play.google.com/store/apps/details?" + "id=org.evolonline.beta.manaplus"); + config.setValue("rated", true); + if (mNeedForceQuit) + { + client->setState(STATE_FORCE_QUIT); + } + else + { + Game::closeDialogs(); + client->setState(STATE_EXIT); + } + } + else if (Net::getGameHandler()->isConnected() + && mSwitchAccountServer->isSelected()) + { + Game::closeDialogs(); + client->setState(STATE_SWITCH_SERVER); + } + else if (mSwitchCharacter->isSelected()) + { + if (client->getState() == STATE_GAME) + { + Net::getCharServerHandler()->switchCharacter(); + Game::closeDialogs(); + } + } + } + scheduleDelete(); +} + +void QuitDialog::keyPressed(gcn::KeyEvent &keyEvent) +{ + const int actionId = static_cast(&keyEvent)->getActionId(); + int dir = 0; + + switch (actionId) + { + case Input::KEY_GUI_SELECT: + case Input::KEY_GUI_SELECT2: + action(gcn::ActionEvent(nullptr, mOkButton->getActionEventId())); + break; + case Input::KEY_GUI_CANCEL: + action(gcn::ActionEvent(nullptr, + mCancelButton->getActionEventId())); + break; + case Input::KEY_GUI_UP: + dir = -1; + break; + case Input::KEY_GUI_DOWN: + dir = 1; + break; + default: + break; + } + + if (dir != 0) + { + std::vector::const_iterator it = mOptions.begin(); + const std::vector::const_iterator + it_end = mOptions.end(); + + for (; it < it_end; ++it) + { + if ((*it)->isSelected()) + break; + } + + if (it == mOptions.end()) + { + if (mOptions[0]) + mOptions[0]->setSelected(true); + return; + } + else if (it == mOptions.begin() && dir < 0) + { + it = mOptions.end(); + } + + it += dir; + + if (it == mOptions.end()) + it = mOptions.begin(); + + (*it)->setSelected(true); + } +} diff --git a/src/gui/windows/quitdialog.h b/src/gui/windows/quitdialog.h new file mode 100644 index 000000000..b0bde98fc --- /dev/null +++ b/src/gui/windows/quitdialog.h @@ -0,0 +1,83 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_QUITDIALOG_H +#define GUI_QUITDIALOG_H + +#include "gui/widgets/window.h" + +#include +#include + +#include + +class Button; +class RadioButton; + +/** + * The quit dialog. + * + * \ingroup Interface + */ +class QuitDialog final : public Window, public gcn::ActionListener, + public gcn::KeyListener +{ + public: + /** + * Constructor + * + * @pointerToMe will be set to NULL when the QuitDialog is destroyed + */ + explicit QuitDialog(QuitDialog **const pointerToMe); + + A_DELETE_COPY(QuitDialog) + + /** + * Destructor + */ + ~QuitDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + void keyPressed(gcn::KeyEvent &keyEvent) override; + + private: + void placeOption(ContainerPlacer &placer, + RadioButton *const option); + std::vector mOptions; + + RadioButton *mLogoutQuit; + RadioButton *mForceQuit; + RadioButton *mSwitchAccountServer; + RadioButton *mSwitchCharacter; + RadioButton *mRate; + Button *mOkButton; + Button *mCancelButton; + + QuitDialog **mMyPointer; + bool mNeedForceQuit; +}; + +#endif // GUI_QUITDIALOG_H diff --git a/src/gui/windows/registerdialog.cpp b/src/gui/windows/registerdialog.cpp new file mode 100644 index 000000000..841b3768f --- /dev/null +++ b/src/gui/windows/registerdialog.cpp @@ -0,0 +1,316 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/registerdialog.h" + +#include "client.h" + +#include "input/keydata.h" +#include "input/keyevent.h" + +#include "gui/windows/okdialog.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/label.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/passwordfield.h" +#include "gui/widgets/radiobutton.h" + +#include "net/logindata.h" +#include "net/loginhandler.h" +#include "net/net.h" + +#include "utils/gettext.h" + +#include "debug.h" + +WrongDataNoticeListener::WrongDataNoticeListener(): + gcn::ActionListener(), + mTarget(nullptr) +{ +} + +void WrongDataNoticeListener::setTarget(TextField *const textField) +{ + mTarget = textField; +} + +void WrongDataNoticeListener::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "ok" && mTarget) + mTarget->requestFocus(); +} + +RegisterDialog::RegisterDialog(LoginData *const data) : + // TRANSLATORS: register dialog name + Window(_("Register"), false, nullptr, "register.xml"), + gcn::ActionListener(), + gcn::KeyListener(), + mLoginData(data), + mUserField(new TextField(this, mLoginData->username)), + mPasswordField(new PasswordField(this, mLoginData->password)), + mConfirmField(new PasswordField(this)), + mEmailField(nullptr), + // TRANSLATORS: register dialog. button. + mRegisterButton(new Button(this, _("Register"), "register", this)), + // TRANSLATORS: register dialog. button. + mCancelButton(new Button(this, _("Cancel"), "cancel", this)), + mMaleButton(nullptr), + mFemaleButton(nullptr), + mOtherButton(nullptr), + mWrongDataNoticeListener(new WrongDataNoticeListener) +{ + setCloseButton(true); + + const int optionalActions = Net::getLoginHandler()-> + supportedOptionalActions(); + + // TRANSLATORS: register dialog. label. + Label *const userLabel = new Label(this, _("Name:")); + // TRANSLATORS: register dialog. label. + Label *const passwordLabel = new Label(this, _("Password:")); + // TRANSLATORS: register dialog. label. + Label *const confirmLabel = new Label(this, _("Confirm:")); + + ContainerPlacer placer; + placer = getPlacer(0, 0); + placer(0, 0, userLabel); + placer(0, 1, passwordLabel); + placer(0, 2, confirmLabel); + + placer(1, 0, mUserField, 3).setPadding(2); + placer(1, 1, mPasswordField, 3).setPadding(2); + placer(1, 2, mConfirmField, 3).setPadding(2); + + int row = 3; + + if (optionalActions & Net::LoginHandler::SetGenderOnRegister) + { + // TRANSLATORS: register dialog. button. + mMaleButton = new RadioButton(this, _("Male"), "sex", true); + // TRANSLATORS: register dialog. button. + mFemaleButton = new RadioButton(this, _("Female"), "sex", false); + if (serverVersion >= 5) + { + // TRANSLATORS: register dialog. button. + mOtherButton = new RadioButton(this, _("Other"), "sex", false); + placer(0, row, mMaleButton); + placer(1, row, mFemaleButton); + placer(2, row, mOtherButton); + } + else + { + placer(1, row, mMaleButton); + placer(2, row, mFemaleButton); + } + + row++; + } + + if (optionalActions & Net::LoginHandler::SetEmailOnRegister) + { + // TRANSLATORS: register dialog. label. + Label *const emailLabel = new Label(this, _("Email:")); + mEmailField = new TextField(this); + placer(0, row, emailLabel); + placer(1, row, mEmailField, 3).setPadding(2); +// row++; + } + + placer = getPlacer(0, 2); + placer(1, 0, mRegisterButton); + placer(2, 0, mCancelButton); + reflowLayout(250, 0); + + mUserField->addKeyListener(this); + mPasswordField->addKeyListener(this); + mConfirmField->addKeyListener(this); + + mUserField->setActionEventId("register"); + mPasswordField->setActionEventId("register"); + mConfirmField->setActionEventId("register"); + + mUserField->addActionListener(this); + mPasswordField->addActionListener(this); + mConfirmField->addActionListener(this); + + center(); + setVisible(true); + mUserField->requestFocus(); + mUserField->setCaretPosition(static_cast( + mUserField->getText().length())); + + mRegisterButton->setEnabled(canSubmit()); +} + +RegisterDialog::~RegisterDialog() +{ + delete mWrongDataNoticeListener; + mWrongDataNoticeListener = nullptr; +} + +void RegisterDialog::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "cancel") + { + close(); + } + else if (eventId == "register" && canSubmit()) + { + const std::string user = mUserField->getText(); + logger->log("RegisterDialog::register Username is %s", user.c_str()); + + std::string errorMsg; + int error = 0; + + const unsigned int minUser = Net::getLoginHandler() + ->getMinUserNameLength(); + const unsigned int maxUser = Net::getLoginHandler() + ->getMaxUserNameLength(); + const unsigned int minPass = Net::getLoginHandler() + ->getMinPasswordLength(); + const unsigned int maxPass = Net::getLoginHandler() + ->getMaxPasswordLength(); + + if (user.length() < minUser) + { + // Name too short + errorMsg = strprintf + // TRANSLATORS: error message + (_("The username needs to be at least %u characters long."), + minUser); + error = 1; + } + else if (user.length() > maxUser - 1) + { + // Name too long + errorMsg = strprintf + // TRANSLATORS: error message + (_("The username needs to be less than %u characters long."), + maxUser); + error = 1; + } + else if (mPasswordField->getText().length() < minPass) + { + // Pass too short + errorMsg = strprintf + // TRANSLATORS: error message + (_("The password needs to be at least %u characters long."), + minPass); + error = 2; + } + else if (mPasswordField->getText().length() > maxPass) + { + // Pass too long + errorMsg = strprintf + // TRANSLATORS: error message + (_("The password needs to be less than %u characters long."), + maxPass); + error = 2; + } + else if (mPasswordField->getText() != mConfirmField->getText()) + { + // Password does not match with the confirmation one + // TRANSLATORS: error message + errorMsg = _("Passwords do not match."); + error = 2; + } + + if (error > 0) + { + if (error == 1) + { + mWrongDataNoticeListener->setTarget(this->mUserField); + } + else if (error == 2) + { + // Reset password confirmation + mPasswordField->setText(""); + mConfirmField->setText(""); + mWrongDataNoticeListener->setTarget(this->mPasswordField); + } + + OkDialog *const dlg = new OkDialog( + // TRANSLATORS: error message + _("Error"), errorMsg, DIALOG_ERROR); + dlg->addActionListener(mWrongDataNoticeListener); + } + else + { + // No errors detected, register the new user. + mRegisterButton->setEnabled(false); + mLoginData->username = mUserField->getText(); + mLoginData->password = mPasswordField->getText(); + if (mFemaleButton && mFemaleButton->isSelected()) + mLoginData->gender = GENDER_FEMALE; + else if (mOtherButton && mOtherButton->isSelected()) + mLoginData->gender = GENDER_OTHER; + else + mLoginData->gender = GENDER_MALE; + + if (mEmailField) + mLoginData->email = mEmailField->getText(); + mLoginData->registerLogin = true; + + client->setState(STATE_REGISTER_ATTEMPT); + } + } +} + +void RegisterDialog::keyPressed(gcn::KeyEvent &keyEvent) +{ + if (keyEvent.isConsumed()) + { + mRegisterButton->setEnabled(canSubmit()); + return; + } + const int actionId = static_cast( + &keyEvent)->getActionId(); + if (actionId == static_cast(Input::KEY_GUI_CANCEL)) + { + action(gcn::ActionEvent(nullptr, mCancelButton->getActionEventId())); + } + else if (actionId == static_cast(Input::KEY_GUI_SELECT) + || actionId == static_cast(Input::KEY_GUI_SELECT2)) + { + action(gcn::ActionEvent(nullptr, mRegisterButton->getActionEventId())); + } + else + { + mRegisterButton->setEnabled(canSubmit()); + } +} + +bool RegisterDialog::canSubmit() const +{ + return !mUserField->getText().empty() && + !mPasswordField->getText().empty() && + !mConfirmField->getText().empty() && + client->getState() == STATE_REGISTER; +} + +void RegisterDialog::close() +{ + client->setState(STATE_LOGIN); + Window::close(); +} diff --git a/src/gui/windows/registerdialog.h b/src/gui/windows/registerdialog.h new file mode 100644 index 000000000..0bc06b92d --- /dev/null +++ b/src/gui/windows/registerdialog.h @@ -0,0 +1,112 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_REGISTERDIALOG_H +#define GUI_REGISTERDIALOG_H + +#include "gui/widgets/window.h" + +#include +#include + +class Button; +class LoginData; +class RadioButton; +class TextField; + +/** + * Listener used while dealing with wrong data. It is used to direct the focus + * to the field which contained wrong data when the Ok button was pressed on + * the error notice. + */ +class WrongDataNoticeListener final : public gcn::ActionListener +{ + public: + WrongDataNoticeListener(); + + A_DELETE_COPY(WrongDataNoticeListener) + + void setTarget(TextField *const textField); + + void action(const gcn::ActionEvent &event) override; + private: + TextField *mTarget; +}; + +/** + * The registration dialog. + * + * \ingroup Interface + */ +class RegisterDialog final : public Window, + public gcn::ActionListener, + public gcn::KeyListener +{ + public: + /** + * Constructor. Name, password and server fields will be initialized to + * the information already present in the LoginData instance. + * + * @see Window::Window + */ + explicit RegisterDialog(LoginData *const loginData); + + A_DELETE_COPY(RegisterDialog) + + /** + * Destructor + */ + ~RegisterDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + /** + * Called when a key is pressed in one of the text fields. + */ + void keyPressed(gcn::KeyEvent &keyEvent) override; + + void close() override; + + private: + /** + * Returns whether submit can be enabled. This is true in the register + * state, when all necessary fields have some text. + */ + bool canSubmit() const; + + LoginData *mLoginData; + TextField *mUserField; + TextField *mPasswordField; + TextField *mConfirmField; + TextField *mEmailField; + Button *mRegisterButton; + Button *mCancelButton; + RadioButton *mMaleButton; + RadioButton *mFemaleButton; + RadioButton *mOtherButton; + WrongDataNoticeListener *mWrongDataNoticeListener; +}; + +#endif // GUI_REGISTERDIALOG_H diff --git a/src/gui/windows/selldialog.cpp b/src/gui/windows/selldialog.cpp new file mode 100644 index 000000000..6c0edbe74 --- /dev/null +++ b/src/gui/windows/selldialog.cpp @@ -0,0 +1,389 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/selldialog.h" + +#include "shopitem.h" +#include "units.h" + +#include "being/playerinfo.h" + +#include "gui/windows/confirmdialog.h" +#include "gui/windows/tradewindow.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/label.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/scrollarea.h" +#include "gui/widgets/shopitems.h" +#include "gui/widgets/shoplistbox.h" +#include "gui/widgets/slider.h" + +#include "net/buysellhandler.h" +#include "net/net.h" +#include "net/npchandler.h" + +#include "resources/iteminfo.h" + +#include "utils/gettext.h" + +#include "debug.h" + +SellDialog::DialogList SellDialog::instances; + +SellDialog::SellDialog(const int npcId) : + // TRANSLATORS: sell dialog name + Window(_("Sell"), false, nullptr, "sell.xml"), + gcn::ActionListener(), + gcn::SelectionListener(), + mNpcId(npcId), mMaxItems(0), mAmountItems(0), mNick("") +{ + init(); +} + +SellDialog::SellDialog(std::string nick): + // TRANSLATORS: sell dialog name + Window(_("Sell"), false, nullptr, "sell.xml"), + gcn::ActionListener(), + gcn::SelectionListener(), + mNpcId(-1), mMaxItems(0), mAmountItems(0), mNick(nick) +{ + init(); +} + +void SellDialog::init() +{ + setWindowName("Sell"); + setResizable(true); + setCloseButton(true); + setStickyButtonLock(true); + setMinWidth(260); + setMinHeight(220); + setDefaultSize(260, 230, ImageRect::CENTER); + + // Create a ShopItems instance, that is aware of duplicate entries. + mShopItems = new ShopItems(true); + + mShopItemList = new ShopListBox(this, mShopItems, mShopItems); + mShopItemList->setProtectItems(true); + mScrollArea = new ScrollArea(mShopItemList, + getOptionBool("showbackground"), "sell_background.xml"); + mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + + mSlider = new Slider(1.0); + + mQuantityLabel = new Label(this, strprintf( + "%d / %d", mAmountItems, mMaxItems)); + mQuantityLabel->setAlignment(gcn::Graphics::CENTER); + // TRANSLATORS: sell dialog label + mMoneyLabel = new Label(this, strprintf(_("Price: %s / Total: %s"), + "", "")); + + // TRANSLATORS: sell dialog button + mIncreaseButton = new Button(this, _("+"), "inc", this); + // TRANSLATORS: sell dialog button + mDecreaseButton = new Button(this, _("-"), "dec", this); + // TRANSLATORS: sell dialog button + mSellButton = new Button(this, _("Sell"), "presell", this); + // TRANSLATORS: sell dialog button + mQuitButton = new Button(this, _("Quit"), "quit", this); + // TRANSLATORS: sell dialog button + mAddMaxButton = new Button(this, _("Max"), "max", this); + + mDecreaseButton->adjustSize(); + mDecreaseButton->setWidth(mIncreaseButton->getWidth()); + + mIncreaseButton->setEnabled(false); + mDecreaseButton->setEnabled(false); + mSellButton->setEnabled(false); + mSlider->setEnabled(false); + + mShopItemList->setDistributeMousePressed(false); + mShopItemList->setPriceCheck(false); + mShopItemList->addSelectionListener(this); + mShopItemList->setActionEventId("sell"); + mShopItemList->addActionListener(this); + + mSlider->setActionEventId("slider"); + mSlider->addActionListener(this); + + ContainerPlacer placer; + placer = getPlacer(0, 0); + + placer(0, 0, mScrollArea, 8, 5).setPadding(3); + placer(0, 5, mDecreaseButton); + placer(1, 5, mSlider, 3); + placer(4, 5, mIncreaseButton); + placer(5, 5, mQuantityLabel, 2); + placer(7, 5, mAddMaxButton); + placer(0, 6, mMoneyLabel, 8); + placer(6, 7, mSellButton); + placer(7, 7, mQuitButton); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + + center(); + loadWindowState(); + + instances.push_back(this); + setVisible(true); + enableVisibleSound(true); +} + +SellDialog::~SellDialog() +{ + delete mShopItems; + mShopItems = nullptr; + instances.remove(this); +} + +void SellDialog::reset() +{ + mShopItems->clear(); + mSlider->setValue(0); + mShopItemList->setSelected(-1); + updateButtonsAndLabels(); +} + +void SellDialog::addItem(const Item *const item, const int price) +{ + if (!item) + return; + + mShopItems->addItem2(item->getInvIndex(), item->getId(), + item->getColor(), item->getQuantity(), price); + + mShopItemList->adjustSize(); +} + +void SellDialog::addItem(const int id, const unsigned char color, + const int amount, const int price) +{ + mShopItems->addItem(id, color, amount, price); + mShopItemList->adjustSize(); +} + + +void SellDialog::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + + if (eventId == "quit") + { + close(); + return; + } + + const int selectedItem = mShopItemList->getSelected(); + + // The following actions require a valid item selection + if (selectedItem == -1 + || selectedItem >= mShopItems->getNumberOfElements()) + { + return; + } + + if (eventId == "slider") + { + mAmountItems = static_cast(mSlider->getValue()); + updateButtonsAndLabels(); + } + else if (eventId == "inc" && mAmountItems < mMaxItems) + { + mAmountItems++; + mSlider->setValue(mAmountItems); + updateButtonsAndLabels(); + } + else if (eventId == "dec" && mAmountItems > 1) + { + mAmountItems--; + mSlider->setValue(mAmountItems); + updateButtonsAndLabels(); + } + else if (eventId == "max") + { + mAmountItems = mMaxItems; + mSlider->setValue(mAmountItems); + updateButtonsAndLabels(); + } + else if ((eventId == "presell" || eventId == "sell" || eventId == "yes") + && mAmountItems > 0 && mAmountItems <= mMaxItems) + { + if (mNpcId != -1) + { + ShopItem *const item = mShopItems->at(selectedItem); + if (PlayerInfo::isItemProtected(item->getId())) + return; + if (eventId == "presell") + { + const ItemInfo &info = ItemDB::get(item->getId()); + if (info.isProtected()) + { + ConfirmDialog *const dialog = new ConfirmDialog( + // TRANSLATORS: sell confirmation header + _("sell item"), + // TRANSLATORS: sell confirmation message + strprintf(_("Do you really want to sell %s?"), + info.getName().c_str()), SOUND_REQUEST, false, true); + dialog->addActionListener(this); + return; + } + } + // Attempt sell + mPlayerMoney += + mAmountItems * mShopItems->at(selectedItem)->getPrice(); + mMaxItems -= mAmountItems; + while (mAmountItems > 0) + { +#ifdef MANASERV_SUPPORT + // This order is important, item->getCurrentInvIndex() would + // return the inventory index of the next Duplicate otherwise. + int itemIndex = item->getCurrentInvIndex(); + const int sellCount = item->sellCurrentDuplicate(mAmountItems); + // For Manaserv, the Item id is to be given as index. + if ((Net::getNetworkType() == ServerInfo::MANASERV)) + itemIndex = item->getId(); +#else + // This order is important, item->getCurrentInvIndex() would + // return the inventory index of the next Duplicate otherwise. + const int itemIndex = item->getCurrentInvIndex(); + const int sellCount = item->sellCurrentDuplicate(mAmountItems); +#endif + Net::getNpcHandler()->sellItem(mNpcId, itemIndex, sellCount); + mAmountItems -= sellCount; + } + + mPlayerMoney += + mAmountItems * mShopItems->at(selectedItem)->getPrice(); + mAmountItems = 1; + mSlider->setValue(0); + + if (mMaxItems) + { + updateButtonsAndLabels(); + } + else + { + // All were sold + mShopItemList->setSelected(-1); + delete mShopItems->at(selectedItem); + mShopItems->erase(selectedItem); + + gcn::Rectangle scroll; + scroll.y = mShopItemList->getRowHeight() * (selectedItem + 1); + scroll.height = mShopItemList->getRowHeight(); + mShopItemList->showPart(scroll); + } + } + else + { + ShopItem *const item = mShopItems->at(selectedItem); + Net::getBuySellHandler()->sendSellRequest(mNick, + item, mAmountItems); + + if (tradeWindow) + tradeWindow->addAutoItem(mNick, item, mAmountItems); + } + } +} + +void SellDialog::valueChanged(const gcn::SelectionEvent &event A_UNUSED) +{ + // Reset amount of items and update labels + mAmountItems = 1; + mSlider->setValue(0); + + updateButtonsAndLabels(); + mSlider->setScale(1, mMaxItems); +} + +void SellDialog::setMoney(const int amount) +{ + mPlayerMoney = amount; + mShopItemList->setPlayersMoney(amount); +} + +void SellDialog::updateButtonsAndLabels() +{ + const int selectedItem = mShopItemList->getSelected(); + int income = 0; + ShopItem *item = nullptr; + + if (selectedItem > -1 && mShopItems->at(selectedItem)) + { + item = mShopItems->at(selectedItem); + if (item) + { + mMaxItems = item->getQuantity(); + if (mAmountItems > mMaxItems) + mAmountItems = mMaxItems; + income = mAmountItems * mShopItems->at(selectedItem)->getPrice(); + } + else + { + mMaxItems = 0; + mAmountItems = 0; + } + } + else + { + mMaxItems = 0; + mAmountItems = 0; + } + + // Update Buttons and slider + mSellButton->setEnabled(mAmountItems > 0); + mDecreaseButton->setEnabled(mAmountItems > 1); + mIncreaseButton->setEnabled(mAmountItems < mMaxItems); + mSlider->setEnabled(mMaxItems > 1); + + // Update the quantity and money labels + mQuantityLabel->setCaption(strprintf("%d / %d", mAmountItems, mMaxItems)); + // TRANSLATORS: sell dialog label + mMoneyLabel->setCaption(strprintf(_("Price: %s / Total: %s"), + Units::formatCurrency(income).c_str(), + Units::formatCurrency(mPlayerMoney + income).c_str())); + if (item) + item->update(); +} + +void SellDialog::setVisible(bool visible) +{ + Window::setVisible(visible); + + if (visible) + { + if (mShopItemList) + mShopItemList->requestFocus(); + } + else + { + scheduleDelete(); + } +} + +void SellDialog::closeAll() +{ + FOR_EACH (DialogList::const_iterator, it, instances) + (*it)->close(); +} diff --git a/src/gui/windows/selldialog.h b/src/gui/windows/selldialog.h new file mode 100644 index 000000000..532244845 --- /dev/null +++ b/src/gui/windows/selldialog.h @@ -0,0 +1,147 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_SELLDIALOG_H +#define GUI_SELLDIALOG_H + +#include "gui/widgets/window.h" + +#include +#include + +class Button; +class Item; +class Label; +class ScrollArea; +class ShopItems; +class ShopListBox; +class Slider; + +/** + * The sell dialog. + * + * \ingroup Interface + */ +class SellDialog final : public Window, + private gcn::ActionListener, + private gcn::SelectionListener +{ + public: + /** + * Constructor. + * + * @see Window::Window + */ + explicit SellDialog(const int npcId); + + /** + * Constructor. + */ + explicit SellDialog(std::string nick); + + A_DELETE_COPY(SellDialog) + + /** + * Destructor + */ + ~SellDialog(); + + void init(); + + /** + * Resets the dialog, clearing inventory. + */ + void reset(); + + /** + * Adds an item to the inventory. + */ + void addItem(const Item *const item, const int price); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + /** + * Updates labels according to selected item. + * + * @see SelectionListener::selectionChanged + */ + void valueChanged(const gcn::SelectionEvent &event) override; + + /** + * Gives Player's Money amount + */ + void setMoney(const int amount); + + /** + * Sets the visibility of this window. + */ + void setVisible(bool visible) override; + + void addItem(const int id, const unsigned char color, + const int amount, const int price); + + /** + * Returns true if any instances exist. + */ + static bool isActive() A_WARN_UNUSED + { return !instances.empty(); } + + /** + * Closes all instances. + */ + static void closeAll(); + + private: + typedef std::list DialogList; + static DialogList instances; + + /** + * Updates the state of buttons and labels. + */ + void updateButtonsAndLabels(); + + int mNpcId; + + Button *mSellButton; + Button *mQuitButton; + Button *mAddMaxButton; + Button *mIncreaseButton; + Button *mDecreaseButton; + ShopListBox *mShopItemList; + ScrollArea *mScrollArea; + Label *mMoneyLabel; + Label *mQuantityLabel; + Slider *mSlider; + + ShopItems *mShopItems; + int mPlayerMoney; + + int mMaxItems; + int mAmountItems; + + std::string mNick; +}; + +#endif // GUI_SELLDIALOG_H diff --git a/src/gui/windows/serverdialog.cpp b/src/gui/windows/serverdialog.cpp new file mode 100644 index 000000000..96eb20562 --- /dev/null +++ b/src/gui/windows/serverdialog.cpp @@ -0,0 +1,867 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/serverdialog.h" + +#include "chatlogger.h" +#include "client.h" +#include "configuration.h" +#include "main.h" + +#include "input/keydata.h" +#include "input/keyevent.h" + +#include "gui/gui.h" +#include "gui/sdlfont.h" + +#include "gui/windows/editserverdialog.h" +#include "gui/windows/logindialog.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/label.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/listbox.h" +#include "gui/widgets/scrollarea.h" + +#include "utils/gettext.h" +#include "utils/langs.h" + +#include + +#include + +#include "debug.h" + +static const int MAX_SERVERLIST = 15; + +static std::string serverTypeToString(const ServerInfo::Type type) +{ + switch (type) + { + case ServerInfo::TMWATHENA: + return "TmwAthena"; + case ServerInfo::EVOL: + return "Evol"; +#ifdef EATHENA_SUPPORT + case ServerInfo::EATHENA: + return "eAthena"; +#endif +#ifdef MANASERV_SUPPORT + case ServerInfo::MANASERV: + return "ManaServ"; +#else + case ServerInfo::MANASERV: +#endif +#ifndef EATHENA_SUPPORT + case ServerInfo::EATHENA: +#endif + default: + case ServerInfo::UNKNOWN: + return ""; + } +} + +static uint16_t defaultPortForServerType(const ServerInfo::Type type) +{ + switch (type) + { + default: + case ServerInfo::EATHENA: +#ifdef EATHENA_SUPPORT + return 6900; +#else + return 6901; +#endif + case ServerInfo::UNKNOWN: + case ServerInfo::TMWATHENA: + case ServerInfo::EVOL: +#ifdef MANASERV_SUPPORT + return 6901; + case ServerInfo::MANASERV: + return 9601; +#else + case ServerInfo::MANASERV: + return 6901; +#endif + } +} + +ServersListModel::ServersListModel(ServerInfos *const servers, + ServerDialog *const parent) : + mServers(servers), + mVersionStrings(servers->size(), VersionString(0, "")), + mParent(parent) +{ +} + +int ServersListModel::getNumberOfElements() +{ + MutexLocker lock = mParent->lock(); + return static_cast(mServers->size()); +} + +std::string ServersListModel::getElementAt(int elementIndex) +{ + MutexLocker lock = mParent->lock(); + const ServerInfo &server = mServers->at(elementIndex); + std::string myServer; + myServer.append(server.hostname); + return myServer; +} + +void ServersListModel::setVersionString(const int index, + const std::string &version) +{ + if (index < 0 || index >= static_cast(mVersionStrings.size())) + return; + + if (version.empty()) + { + mVersionStrings[index] = VersionString(0, ""); + } + else + { + mVersionStrings[index] = VersionString( + gui->getFont()->getWidth(version), version); + } +} + +class ServersListBox final : public ListBox +{ +public: + ServersListBox(const Widget2 *const widget, + ServersListModel *const model) : + ListBox(widget, model, "serverslistbox.xml"), + mNotSupportedColor(getThemeColor(Theme::SERVER_VERSION_NOT_SUPPORTED)), + mNotSupportedColor2(getThemeColor( + Theme::SERVER_VERSION_NOT_SUPPORTED_OUTLINE)) + { + mHighlightColor = getThemeColor(Theme::HIGHLIGHT); + } + + void draw(gcn::Graphics *graphics) override + { + if (!mListModel) + return; + + ServersListModel *const model = static_cast( + mListModel); + Graphics *const g = static_cast(graphics); + + updateAlpha(); + + mHighlightColor.a = static_cast(mAlpha * 255.0F); + g->setColor(mHighlightColor); + + const int height = getRowHeight(); + mNotSupportedColor.a = static_cast(mAlpha * 255.0F); + + // Draw filled rectangle around the selected list element + if (mSelected >= 0) + { + graphics->fillRectangle(gcn::Rectangle(mPadding, + height * mSelected + mPadding, getWidth() - 2 * mPadding, + height)); + } + + gcn::Font *const font1 = boldFont; + gcn::Font *const font2 = getFont(); + const int fontHeight = font1->getHeight(); + const int pad1 = fontHeight + mPadding; + const int pad2 = height / 4 + mPadding; + const int width = getWidth(); + // Draw the list elements + for (int i = 0, y = 0; i < model->getNumberOfElements(); + ++i, y += height) + { + const ServerInfo &info = model->getServer(i); + + if (mSelected == i) + { + g->setColorAll(mForegroundSelectedColor, + mForegroundSelectedColor2); + } + else + { + g->setColorAll(mForegroundColor, mForegroundColor2); + } + + int top; + int x = mPadding; + + if (!info.name.empty()) + { + x += font1->getWidth(info.name) + 15; + font1->drawString(graphics, info.name, mPadding, y + mPadding); + top = y + pad1; + } + else + { + top = y + pad2; + } + + if (!info.description.empty()) + font2->drawString(graphics, info.description, x, y + mPadding); + font2->drawString(graphics, model->getElementAt(i), mPadding, top); + + if (info.version.first > 0) + { + g->setColorAll(mNotSupportedColor, mNotSupportedColor2); + font2->drawString(graphics, info.version.second, + width - info.version.first - mPadding, top); + } + } + } + + unsigned int getRowHeight() const override + { + return 2 * getFont()->getHeight() + 5; + } +private: + gcn::Color mNotSupportedColor; + gcn::Color mNotSupportedColor2; +}; + + +ServerDialog::ServerDialog(ServerInfo *const serverInfo, + const std::string &dir) : + // TRANSLATORS: servers dialog name + Window(_("Choose Your Server"), false, nullptr, "server.xml"), + gcn::ActionListener(), + gcn::KeyListener(), + gcn::SelectionListener(), + mMutex(), + mDescription(new Label(this, std::string())), + // TRANSLATORS: servers dialog button + mQuitButton(new Button(this, _("Quit"), "quit", this)), + // TRANSLATORS: servers dialog button + mConnectButton(new Button(this, _("Connect"), "connect", this)), + // TRANSLATORS: servers dialog button + mAddEntryButton(new Button(this, _("Add"), "addEntry", this)), + // TRANSLATORS: servers dialog button + mEditEntryButton(new Button(this, _("Edit"), "editEntry", this)), + // TRANSLATORS: servers dialog button + mDeleteButton(new Button(this, _("Delete"), "remove", this)), + // TRANSLATORS: servers dialog button + mLoadButton(new Button(this, _("Load"), "load", this)), + mServers(ServerInfos()), + mServersListModel(new ServersListModel(&mServers, this)), + mServersList(new ServersListBox(this, mServersListModel)), + mDir(dir), + mDownloadStatus(DOWNLOADING_UNKNOWN), + mDownload(nullptr), + mDownloadProgress(-1.0F), + mServerInfo(serverInfo), + mPersistentIPCheckBox(nullptr) +{ + if (isSafeMode) + { + // TRANSLATORS: servers dialog name + setCaption(_("Choose Your Server *** SAFE MODE ***")); + } + + setWindowName("ServerDialog"); + + setCloseButton(true); + + mPersistentIPCheckBox = new CheckBox(this, + // TRANSLATORS: servers dialog checkbox + _("Use same ip for game sub servers"), + config.getBoolValue("usePersistentIP"), + this, "persitent ip"); + + loadCustomServers(); + + mServersList->addMouseListener(this); + + ScrollArea *const usedScroll = new ScrollArea(mServersList, + getOptionBool("showbackground"), "server_background.xml"); + usedScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + + mServersList->addSelectionListener(this); + usedScroll->setVerticalScrollAmount(0); + + place(0, 0, usedScroll, 7, 5).setPadding(3); + place(0, 5, mDescription, 7); + place(0, 6, mPersistentIPCheckBox, 7); + place(0, 7, mAddEntryButton); + place(1, 7, mEditEntryButton); + place(2, 7, mLoadButton); + place(3, 7, mDeleteButton); + place(5, 7, mQuitButton); + place(6, 7, mConnectButton); + + // Make sure the list has enough height + getLayout().setRowHeight(0, 80); + + // Do this manually instead of calling reflowLayout so we can enforce a + // minimum width. + int width = 500; + int height = 350; + + getLayout().reflow(width, height); + setContentSize(width, height); + + setMinWidth(310); + setMinHeight(220); + setDefaultSize(getWidth(), getHeight(), ImageRect::CENTER); + + setResizable(true); + addKeyListener(this); + + loadWindowState(); + + setVisible(true); + + mConnectButton->requestFocus(); + + loadServers(true); + + mServersList->setSelected(0); // Do this after for the Delete button + + if (needUpdateServers()) + downloadServerList(); +} + +ServerDialog::~ServerDialog() +{ + if (mDownload) + { + mDownload->cancel(); + delete mDownload; + mDownload = nullptr; + } + delete mServersListModel; + mServersListModel = nullptr; +} + +void ServerDialog::connectToSelectedServer() +{ + if (client->getState() == STATE_CONNECT_SERVER) + return; + + const int index = mServersList->getSelected(); + if (index < 0) + return; + + if (mDownload) + mDownload->cancel(); + + mQuitButton->setEnabled(false); + mConnectButton->setEnabled(false); + mLoadButton->setEnabled(false); + + ServerInfo server = mServers.at(index); + mServerInfo->hostname = server.hostname; + mServerInfo->althostname = server.althostname; + mServerInfo->port = server.port; + mServerInfo->type = server.type; + mServerInfo->name = server.name; + mServerInfo->description = server.description; + mServerInfo->registerUrl = server.registerUrl; + mServerInfo->onlineListUrl = server.onlineListUrl; + mServerInfo->supportUrl = server.supportUrl; + mServerInfo->save = true; + + if (chatLogger) + chatLogger->setServerName(mServerInfo->hostname); + + saveCustomServers(*mServerInfo); + + if (!LoginDialog::savedPasswordKey.empty()) + { + if (mServerInfo->hostname != LoginDialog::savedPasswordKey) + LoginDialog::savedPassword.clear(); + } + + config.setValue("usePersistentIP", + mPersistentIPCheckBox->isSelected()); + client->setState(STATE_CONNECT_SERVER); +} + +void ServerDialog::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "connect") + { + connectToSelectedServer(); + } + else if (eventId == "quit") + { + close(); + } + else if (eventId == "load") + { + downloadServerList(); + } + else if (eventId == "addEntry") + { + new EditServerDialog(this, ServerInfo(), -1); + } + else if (eventId == "editEntry") + { + const int index = mServersList->getSelected(); + if (index >= 0) + new EditServerDialog(this, mServers.at(index), index); + } + else if (eventId == "remove") + { + const int index = mServersList->getSelected(); + if (index >= 0) + { + mServersList->setSelected(0); + mServers.erase(mServers.begin() + index); + saveCustomServers(); + } + } +} + +void ServerDialog::keyPressed(gcn::KeyEvent &keyEvent) +{ + switch (static_cast(&keyEvent)->getActionId()) + { + case Input::KEY_GUI_CANCEL: + keyEvent.consume(); + client->setState(STATE_EXIT); + return; + + case Input::KEY_GUI_SELECT: + case Input::KEY_GUI_SELECT2: + keyEvent.consume(); + action(gcn::ActionEvent(nullptr, + mConnectButton->getActionEventId())); + return; + + case Input::KEY_GUI_INSERT: + new EditServerDialog(this, ServerInfo(), -1); + return; + + case Input::KEY_GUI_DELETE: + { + const int index = mServersList->getSelected(); + if (index >= 0) + { + mServersList->setSelected(0); + mServers.erase(mServers.begin() + index); + saveCustomServers(); + } + return; + } + + case Input::KEY_GUI_BACKSPACE: + { + const int index = mServersList->getSelected(); + if (index >= 0) + new EditServerDialog(this, mServers.at(index), index); + return; + } + + default: + break; + } + if (!keyEvent.isConsumed()) + mServersList->keyPressed(keyEvent); +} + +void ServerDialog::valueChanged(const gcn::SelectionEvent &) +{ + const int index = mServersList->getSelected(); + if (index == -1) + { + mDeleteButton->setEnabled(false); + return; + } + mDeleteButton->setEnabled(true); +} + +void ServerDialog::mouseClicked(gcn::MouseEvent &mouseEvent) +{ + if (mouseEvent.getClickCount() == 2 && + mouseEvent.getSource() == mServersList) + { + action(gcn::ActionEvent(mConnectButton, + mConnectButton->getActionEventId())); + } +} + +void ServerDialog::logic() +{ + BLOCK_START("ServerDialog::logic") + { + MutexLocker tempLock(&mMutex); + if (mDownloadStatus == DOWNLOADING_COMPLETE) + { + mDownloadStatus = DOWNLOADING_OVER; + mDescription->setCaption(std::string()); + } + else if (mDownloadStatus == DOWNLOADING_IN_PROGRESS) + { + // TRANSLATORS: servers dialog label + mDescription->setCaption(strprintf(_("Downloading server list..." + "%2.2f%%"), static_cast(mDownloadProgress * 100))); + } + else if (mDownloadStatus == DOWNLOADING_IDLE) + { + // TRANSLATORS: servers dialog label + mDescription->setCaption(_("Waiting for server...")); + } + else if (mDownloadStatus == DOWNLOADING_PREPARING) + { + // TRANSLATORS: servers dialog label + mDescription->setCaption(_("Preparing download")); + } + else if (mDownloadStatus == DOWNLOADING_ERROR) + { + // TRANSLATORS: servers dialog label + mDescription->setCaption(_("Error retreiving server list!")); + } + } + + Window::logic(); + BLOCK_END("ServerDialog::logic") +} + +void ServerDialog::downloadServerList() +{ + // Try to load the configuration value for the onlineServerList + std::string listFile = branding.getStringValue("onlineServerList"); + + if (listFile.empty()) + listFile = config.getStringValue("onlineServerList"); + + // Fall back to manaplus.org when neither branding + // nor config set it + if (listFile.empty()) + listFile = "http://manaplus.org/serverlist.xml"; + + if (mDownload) + { + mDownload->cancel(); + delete mDownload; + mDownload = nullptr; + } + + mDownload = new Net::Download(this, listFile, &downloadUpdate); + mDownload->setFile(std::string(mDir).append("/").append( + branding.getStringValue("onlineServerFile"))); + mDownload->start(); + + config.setValue("serverslistupdate", getDateString()); +} + +void ServerDialog::loadServers(const bool addNew) +{ + XML::Document doc(std::string(mDir).append("/").append( + branding.getStringValue("onlineServerFile")), false); + const XmlNodePtr rootNode = doc.rootNode(); + + if (!rootNode || !xmlNameEqual(rootNode, "serverlist")) + { + logger->log1("Error loading server list!"); + return; + } + + const int ver = XML::getProperty(rootNode, "version", 0); + if (ver != 1) + { + logger->log("Error: unsupported online server list version: %d", + ver); + return; + } + + const std::string lang = getLangShort(); + const std::string description2("description_" + lang); + + for_each_xml_child_node(serverNode, rootNode) + { + if (!xmlNameEqual(serverNode, "server")) + continue; + + const std::string type = XML::getProperty( + serverNode, "type", "unknown"); + ServerInfo server; + server.type = ServerInfo::parseType(type); + + // Ignore unknown server types + if (server.type == ServerInfo::UNKNOWN) + { + logger->log("Ignoring server entry with unknown type: %s", + type.c_str()); + continue; + } + + server.name = XML::getProperty(serverNode, "name", std::string()); + std::string version = XML::getProperty(serverNode, "minimumVersion", + std::string()); + + const bool meetsMinimumVersion = (compareStrI(version, SMALL_VERSION) + <= 0); + + // For display in the list + if (meetsMinimumVersion) + version.clear(); + else if (version.empty()) + { + // TRANSLATORS: servers dialog label + version = _("requires a newer version"); + } + else + { + // TRANSLATORS: servers dialog label + version = strprintf(_("requires v%s"), version.c_str()); + } + + const gcn::Font *const font = gui->getFont(); + + for_each_xml_child_node(subNode, serverNode) + { + if (xmlNameEqual(subNode, "connection")) + { + server.hostname = XML::getProperty(subNode, "hostname", ""); + server.althostname = XML::getProperty( + subNode, "althostname", ""); + server.port = static_cast( + XML::getProperty(subNode, "port", 0)); + + if (server.port == 0) + { + // If no port is given, use the default for the given type + server.port = defaultPortForServerType(server.type); + } + } + else if ((xmlNameEqual(subNode, "description") + && server.description.empty()) || (!lang.empty() + && xmlNameEqual(subNode, description2.c_str()))) + { + server.description = reinterpret_cast( + subNode->xmlChildrenNode->content); + } + else if (xmlNameEqual(subNode, "registerurl")) + { + server.registerUrl = reinterpret_cast( + subNode->xmlChildrenNode->content); + } + else if (xmlNameEqual(subNode, "onlineListUrl")) + { + server.onlineListUrl = reinterpret_cast( + subNode->xmlChildrenNode->content); + } + else if (xmlNameEqual(subNode, "support")) + { + server.supportUrl = reinterpret_cast( + subNode->xmlChildrenNode->content); + } + } + + server.version.first = font->getWidth(version); + server.version.second = version; + + MutexLocker tempLock(&mMutex); + // Add the server to the local list if it's not already present + bool found = false; + for (unsigned int i = 0, sz = static_cast( + mServers.size()); i < sz; i++) + { + if (mServers[i] == server) + { + // Use the name listed in the server list + mServers[i].name = server.name; + mServers[i].version = server.version; + mServers[i].description = server.description; + mServers[i].registerUrl = server.registerUrl; + mServers[i].onlineListUrl = server.onlineListUrl; + mServers[i].supportUrl = server.supportUrl; + mServers[i].althostname = server.althostname; + mServersListModel->setVersionString(i, version); + found = true; + break; + } + } + if (!found && addNew) + mServers.push_back(server); + } + if (mServersList->getSelected() < 0) + mServersList->setSelected(0); +} + +void ServerDialog::loadCustomServers() +{ + for (int i = 0; i < MAX_SERVERLIST; ++i) + { + const std::string index = toString(i); + const std::string nameKey("MostUsedServerDescName" + index); + const std::string descKey("MostUsedServerDescription" + index); + const std::string hostKey("MostUsedServerName" + index); + const std::string typeKey("MostUsedServerType" + index); + const std::string portKey("MostUsedServerPort" + index); + const std::string onlineListUrlKey + ("MostUsedServerOnlineList" + index); + + ServerInfo server; + server.name = config.getValue(nameKey, ""); + server.description = config.getValue(descKey, ""); + server.onlineListUrl = config.getValue(onlineListUrlKey, ""); + server.hostname = config.getValue(hostKey, ""); + server.type = ServerInfo::parseType(config.getValue(typeKey, "")); + + const int defaultPort = defaultPortForServerType(server.type); + server.port = static_cast( + config.getValue(portKey, defaultPort)); + + // skip invalid server + if (!server.isValid()) + continue; + + server.save = true; + mServers.push_back(server); + } +} + +void ServerDialog::saveCustomServers(const ServerInfo ¤tServer, + const int index) +{ + // Make sure the current server is mentioned first + if (currentServer.isValid()) + { + if (index >= 0 && static_cast(index) < mServers.size()) + { + mServers[index] = currentServer; + } + else + { + FOR_EACH (ServerInfos::iterator, i, mServers) + { + if (*i == currentServer) + { + mServers.erase(i); + break; + } + } + mServers.insert(mServers.begin(), currentServer); + } + } + + int savedServerCount = 0; + + for (unsigned i = 0, sz = static_cast(mServers.size()); + i < sz && savedServerCount < MAX_SERVERLIST; ++ i) + { + const ServerInfo &server = mServers.at(i); + + // Only save servers that were loaded from settings + if (!(server.save && server.isValid())) + continue; + + const std::string num = toString(savedServerCount); + const std::string nameKey("MostUsedServerDescName" + num); + const std::string descKey("MostUsedServerDescription" + num); + const std::string hostKey("MostUsedServerName" + num); + const std::string typeKey("MostUsedServerType" + num); + const std::string portKey("MostUsedServerPort" + num); + const std::string onlineListUrlKey + ("MostUsedServerOnlineList" + num); + + config.setValue(nameKey, toString(server.name)); + config.setValue(descKey, toString(server.description)); + config.setValue(onlineListUrlKey, toString(server.onlineListUrl)); + config.setValue(hostKey, toString(server.hostname)); + config.setValue(typeKey, serverTypeToString(server.type)); + config.setValue(portKey, toString(server.port)); + ++ savedServerCount; + } + + // Insert an invalid entry at the end to make the loading stop there + if (savedServerCount < MAX_SERVERLIST) + config.setValue("MostUsedServerName" + toString(savedServerCount), ""); +} + +int ServerDialog::downloadUpdate(void *ptr, DownloadStatus status, + size_t total, size_t remaining) +{ + if (!ptr || status == DOWNLOAD_STATUS_CANCELLED) + return -1; + + ServerDialog *const sd = reinterpret_cast(ptr); + bool finished = false; + + if (!sd->mDownload) + return -1; + + if (status == DOWNLOAD_STATUS_COMPLETE) + { + finished = true; + } + else if (status < 0) + { + logger->log("Error retreiving server list: %s\n", + sd->mDownload->getError()); + sd->mDownloadStatus = DOWNLOADING_ERROR; + } + else + { + float progress = static_cast(remaining); + if (total) + progress /= static_cast(total); + + if (progress != progress || progress < 0.0F) + progress = 0.0f; + else if (progress > 1.0F) + progress = 1.0F; + + MutexLocker lock1(&sd->mMutex); + sd->mDownloadStatus = DOWNLOADING_IN_PROGRESS; + sd->mDownloadProgress = progress; + } + + if (finished) + { + sd->loadServers(); + MutexLocker lock1(&sd->mMutex); + sd->mDownloadStatus = DOWNLOADING_COMPLETE; + } + + return 0; +} + +void ServerDialog::updateServer(const ServerInfo &server, const int index) +{ + saveCustomServers(server, index); +} + +bool ServerDialog::needUpdateServers() const +{ + if (mServers.empty() || config.getStringValue("serverslistupdate") + != getDateString()) + { + return true; + } + + return false; +} + +void ServerDialog::close() +{ + if (mDownload) + mDownload->cancel(); + client->setState(STATE_FORCE_QUIT); + Window::close(); +} diff --git a/src/gui/windows/serverdialog.h b/src/gui/windows/serverdialog.h new file mode 100644 index 000000000..ea6954e15 --- /dev/null +++ b/src/gui/windows/serverdialog.h @@ -0,0 +1,194 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_SERVERDIALOG_H +#define GUI_SERVERDIALOG_H + +#include "gui/widgets/window.h" +#include "gui/widgets/checkbox.h" + +#include "net/download.h" +#include "net/serverinfo.h" + +#include "utils/mutex.h" + +#include +#include +#include +#include + +#include +#include + +class Button; +class Label; +class ListBox; +class ServerDialog; + +/** + * Server and Port List Model + */ +class ServersListModel final : public gcn::ListModel +{ + public: + typedef std::pair VersionString; + + ServersListModel(ServerInfos *const servers, + ServerDialog *const parent); + + A_DELETE_COPY(ServersListModel) + + /** + * Used to get number of line in the list + */ + int getNumberOfElements() override A_WARN_UNUSED; + + /** + * Used to get an element from the list + */ + std::string getElementAt(int elementIndex) override A_WARN_UNUSED; + + /** + * Used to get the corresponding Server struct + */ + const ServerInfo &getServer(const int elementIndex) const A_WARN_UNUSED + { return mServers->at(elementIndex); } + + void setVersionString(const int index, const std::string &version); + + private: + typedef std::vector VersionStrings; + + ServerInfos *mServers; + VersionStrings mVersionStrings; + ServerDialog *mParent; +}; + + +/** + * The server choice dialog. + * + * \ingroup Interface + */ +class ServerDialog final : public Window, + public gcn::ActionListener, + public gcn::KeyListener, + public gcn::SelectionListener +{ + public: + /** + * Constructor + * + * @see Window::Window + */ + ServerDialog(ServerInfo *const serverInfo, const std::string &dir); + + A_DELETE_COPY(ServerDialog) + + /** + * Destructor + */ + ~ServerDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + void keyPressed(gcn::KeyEvent &keyEvent) override; + + /** + * Called when the selected value changed in the servers list box. + */ + void valueChanged(const gcn::SelectionEvent &event) override; + + void mouseClicked(gcn::MouseEvent &mouseEvent) override; + + void logic() override; + + void updateServer(const ServerInfo &server, const int index); + + void connectToSelectedServer(); + + void close() override; + + protected: + friend class ServersListModel; + + MutexLocker lock() + { return MutexLocker(&mMutex); } + + private: + friend class EditServerDialog; + + /** + * Called to load a list of available server from an online xml file. + */ + void downloadServerList(); + + void loadServers(const bool addNew = true); + + void loadCustomServers(); + + void saveCustomServers(const ServerInfo ¤tServer = ServerInfo(), + const int index = -1); + + bool needUpdateServers() const; + + static int downloadUpdate(void *ptr, DownloadStatus status, + size_t total, size_t remaining); + + Mutex mMutex; + Label *mDescription; + Button *mQuitButton; + Button *mConnectButton; + Button *mAddEntryButton; + Button *mEditEntryButton; + Button *mDeleteButton; + Button *mLoadButton; + + ServerInfos mServers; + ServersListModel *mServersListModel; + ListBox *mServersList; + + const std::string &mDir; + + enum ServerDialogDownloadStatus + { + DOWNLOADING_UNKNOWN = 0, + DOWNLOADING_ERROR, + DOWNLOADING_PREPARING, + DOWNLOADING_IDLE, + DOWNLOADING_IN_PROGRESS, + DOWNLOADING_COMPLETE, + DOWNLOADING_OVER + }; + + /** Status of the current download. */ + ServerDialogDownloadStatus mDownloadStatus; + Net::Download *mDownload; + float mDownloadProgress; + ServerInfo *mServerInfo; + CheckBox *mPersistentIPCheckBox; +}; + +#endif // GUI_SERVERDIALOG_H diff --git a/src/gui/windows/setup.cpp b/src/gui/windows/setup.cpp new file mode 100644 index 000000000..00001424b --- /dev/null +++ b/src/gui/windows/setup.cpp @@ -0,0 +1,255 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/setup.h" + +#include "configuration.h" +#include "game.h" +#include "main.h" +#include "touchmanager.h" + +#include "gui/windows/chatwindow.h" + +#include "gui/setup_audio.h" +#include "gui/setup_chat.h" +#include "gui/setup_colors.h" +#include "gui/setup_joystick.h" +#include "gui/setup_other.h" +#include "gui/setup_theme.h" +#include "gui/setup_input.h" +#include "gui/setup_perfomance.h" +#include "gui/setup_players.h" +#include "gui/setup_relations.h" +#include "gui/setup_touch.h" +#include "gui/setup_video.h" +#include "gui/setup_visual.h" + +#include "gui/widgets/label.h" + +#include "utils/dtor.h" +#include "utils/gettext.h" + +#include "debug.h" + +extern Window *statusWindow; +Setup *setupWindow; + +Setup::Setup() : + // TRANSLATORS: setup window name + Window(_("Setup"), false, nullptr, "setup.xml"), + gcn::ActionListener(), + mTabs(), + mWindowsToReset(), + mButtons(), + mResetWindows(nullptr), + mPanel(new TabbedArea(this)), + mVersion(new Label(this, FULL_VERSION)) +{ + setCloseButton(true); + setResizable(true); + setStickyButtonLock(true); + + int width = 620; + const int height = 450; + + if (config.getIntValue("screenwidth") >= 730) + width += 100; + + setContentSize(width, height); + setMinWidth(310); + setMinHeight(210); + + static const char *buttonNames[] = + { + // TRANSLATORS: setup button + N_("Apply"), + // TRANSLATORS: setup button + N_("Cancel"), + // TRANSLATORS: setup button + N_("Store"), + // TRANSLATORS: setup button + N_("Reset Windows"), + nullptr + }; + int x = width; + const int buttonPadding = getOption("buttonPadding", 5); + for (const char ** curBtn = buttonNames; *curBtn; ++ curBtn) + { + Button *const btn = new Button(this, gettext(*curBtn), *curBtn, this); + mButtons.push_back(btn); + x -= btn->getWidth() + buttonPadding; + btn->setPosition(x, height - btn->getHeight() - buttonPadding); + add(btn); + + // Store this button, as it needs to be enabled/disabled + if (!strcmp(*curBtn, "Reset Windows")) + mResetWindows = btn; + } + + mPanel->setDimension(gcn::Rectangle(5, 5, width - 10, height - 40)); + mPanel->enableScrollButtons(true); + + mTabs.push_back(new Setup_Video(this)); + mTabs.push_back(new Setup_Visual(this)); + mTabs.push_back(new Setup_Audio(this)); + mTabs.push_back(new Setup_Perfomance(this)); + mTabs.push_back(new Setup_Touch(this)); + mTabs.push_back(new Setup_Input(this)); + mTabs.push_back(new Setup_Joystick(this)); + mTabs.push_back(new Setup_Colors(this)); + mTabs.push_back(new Setup_Chat(this)); + mTabs.push_back(new Setup_Players(this)); + mTabs.push_back(new Setup_Relations(this)); + mTabs.push_back(new Setup_Theme(this)); + mTabs.push_back(new Setup_Other(this)); + + FOR_EACH (std::list::const_iterator, i, mTabs) + { + SetupTab *const tab = *i; + mPanel->addTab(tab->getName(), tab); + } + add(mPanel); + + if (mResetWindows) + { + mVersion->setPosition(9, + height - mVersion->getHeight() - mResetWindows->getHeight() - 9); + } + else + { + mVersion->setPosition(9, height - mVersion->getHeight() - 30); + } + add(mVersion); + + center(); + + widgetResized(gcn::Event(nullptr)); + setInGame(false); + enableVisibleSound(true); +} + +Setup::~Setup() +{ + delete_all(mTabs); + mButtons.clear(); +} + +void Setup::action(const gcn::ActionEvent &event) +{ + if (Game::instance()) + Game::instance()->resetAdjustLevel(); + const std::string &eventId = event.getId(); + + if (eventId == "Apply") + { + setVisible(false); + for_each(mTabs.begin(), mTabs.end(), std::mem_fun(&SetupTab::apply)); + } + else if (eventId == "Cancel") + { + doCancel(); + } + else if (eventId == "Store") + { + if (chatWindow) + chatWindow->saveState(); + config.write(); + serverConfig.write(); + } + else if (eventId == "Reset Windows") + { + // Bail out if this action happens to be activated before the windows + // are created (though it should be disabled then) + if (!statusWindow) + return; + + FOR_EACH (std::list::const_iterator, it, mWindowsToReset) + { + if (*it) + (*it)->resetToDefaultSize(); + } + } +} + +void Setup::setInGame(const bool inGame) +{ + mResetWindows->setEnabled(inGame); +} + +void Setup::externalUpdate() +{ + FOR_EACH (std::list::const_iterator, it, mTabs) + { + if (*it) + (*it)->externalUpdated(); + } +} + +void Setup::registerWindowForReset(Window *const window) +{ + mWindowsToReset.push_back(window); +} + +void Setup::doCancel() +{ + setVisible(false); + for_each(mTabs.begin(), mTabs.end(), std::mem_fun(&SetupTab::cancel)); +} + +void Setup::activateTab(const std::string &name) +{ + std::string tmp = gettext(name.c_str()); + mPanel->setSelectedTabByName(tmp); +} + +void Setup::setVisible(bool visible) +{ + touchManager.setTempHide(visible); + Window::setVisible(visible); +} + +void Setup::widgetResized(const gcn::Event &event) +{ + Window::widgetResized(event); + + const gcn::Rectangle area = getChildrenArea(); + int x = area.width; + const int height = area.height; + const int width = area.width; + const int buttonPadding = getOption("buttonPadding", 5); + mPanel->setDimension(gcn::Rectangle(5, 5, width - 10, height - 40)); + FOR_EACH (std::vector::iterator, it, mButtons) + { + Button *const btn = *it; + x -= btn->getWidth() + buttonPadding; + btn->setPosition(x, height - btn->getHeight() - buttonPadding); + } + if (mResetWindows) + { + mVersion->setPosition(9, + height - mVersion->getHeight() - mResetWindows->getHeight() - 9); + } + else + { + mVersion->setPosition(9, height - mVersion->getHeight() - 30); + } +} diff --git a/src/gui/windows/setup.h b/src/gui/windows/setup.h new file mode 100644 index 000000000..aeb7cc635 --- /dev/null +++ b/src/gui/windows/setup.h @@ -0,0 +1,82 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_SETUP_H +#define GUI_SETUP_H + +#include "gui/widgets/tabbedarea.h" + +#include "gui/widgets/window.h" + +#include + +#include + +class Label; +class SetupTab; + +/** + * The setup dialog. Displays several tabs for configuring different aspects + * of the game. + * + * \ingroup GUI + */ +class Setup final : public Window, public gcn::ActionListener +{ + public: + Setup(); + + A_DELETE_COPY(Setup) + + ~Setup(); + + void action(const gcn::ActionEvent &event) override; + + void setInGame(const bool inGame); + + void externalUpdate(); + + void registerWindowForReset(Window *const window); + + void clearWindowsForReset() + { mWindowsToReset.clear(); } + + void doCancel(); + + void activateTab(const std::string &name); + + void setVisible(bool visible) override; + + void widgetResized(const gcn::Event &event) override; + + private: + std::list mTabs; + std::list mWindowsToReset; + std::vector mButtons; + Button *mResetWindows; + TabbedArea *mPanel; + Label *mVersion; +}; + +extern Setup* setupWindow; + +#endif // GUI_SETUP_H diff --git a/src/gui/windows/shopwindow.cpp b/src/gui/windows/shopwindow.cpp new file mode 100644 index 000000000..a495d5750 --- /dev/null +++ b/src/gui/windows/shopwindow.cpp @@ -0,0 +1,866 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/buydialog.h" +#include "gui/windows/confirmdialog.h" +#include "gui/windows/itemamountwindow.h" +#include "gui/windows/shopwindow.h" +#include "gui/windows/selldialog.h" +#include "gui/windows/tradewindow.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/chattab.h" +#include "gui/widgets/checkbox.h" +#include "gui/widgets/label.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/scrollarea.h" +#include "gui/widgets/shopitems.h" +#include "gui/widgets/shoplistbox.h" + +#include "actorspritemanager.h" +#include "auctionmanager.h" +#include "client.h" +#include "configuration.h" +#include "inventory.h" +#include "item.h" +#include "shopitem.h" +#include "soundconsts.h" +#include "soundmanager.h" + +#include "being/localplayer.h" +#include "being/playerinfo.h" +#include "being/playerrelations.h" + +#include "net/net.h" +#include "net/chathandler.h" +#include "net/tradehandler.h" + +#include "resources/iteminfo.h" + +#include "utils/gettext.h" + +#include + +#include + +#include "debug.h" + +extern std::string tradePartnerName; +ShopWindow::DialogList ShopWindow::instances; + +ShopWindow::ShopWindow(): + // TRANSLATORS: shop window name + Window(_("Personal Shop"), false, nullptr, "shop.xml"), + gcn::ActionListener(), + gcn::SelectionListener(), + // TRANSLATORS: shop window button + mCloseButton(new Button(this, _("Close"), "close", this)), + mBuyShopItems(new ShopItems), + mSellShopItems(new ShopItems), + mBuyShopItemList(new ShopListBox(this, mBuyShopItems, mBuyShopItems)), + mSellShopItemList(new ShopListBox(this, mSellShopItems, mSellShopItems)), + mBuyScrollArea(new ScrollArea(mBuyShopItemList, + getOptionBool("showbuybackground"), "shop_buy_background.xml")), + mSellScrollArea(new ScrollArea(mSellShopItemList, + getOptionBool("showsellbackground"), "shop_sell_background.xml")), + // TRANSLATORS: shop window label + mBuyLabel(new Label(this, _("Buy items"))), + // TRANSLATORS: shop window label + mSellLabel(new Label(this, _("Sell items"))), + // TRANSLATORS: shop window label + mBuyAddButton(new Button(this, _("Add"), "add buy", this)), + // TRANSLATORS: shop window label + mBuyDeleteButton(new Button(this, _("Delete"), "delete buy", this)), + // TRANSLATORS: shop window label + mBuyAnnounceButton(new Button(this, _("Announce"), "announce buy", this)), + mBuyAuctionButton(nullptr), + // TRANSLATORS: shop window button + mSellAddButton(new Button(this, _("Add"), "add sell", this)), + // TRANSLATORS: shop window button + mSellDeleteButton(new Button(this, _("Delete"), "delete sell", this)), + // TRANSLATORS: shop window button + mSellAnnounceButton(new Button(this, _("Announce"), + "announce sell", this)), + mSellAuctionButton(nullptr), + // TRANSLATORS: shop window checkbox + mAnnounceLinks(new CheckBox(this, _("Show links in announce"), false, + this, "link announce")), + mSelectedItem(-1), + mAnnonceTime(0), + mLastRequestTimeList(0), + mLastRequestTimeItem(0), + mRandCounter(0), + mAcceptPlayer(""), + mTradeItem(nullptr), + mTradeNick(""), + mTradeMoney(0) +{ + setWindowName("Personal Shop"); + setResizable(true); + setCloseButton(true); + setStickyButtonLock(true); + setMinWidth(260); + setMinHeight(220); + if (mainGraphics->mWidth > 600) + setDefaultSize(500, 300, ImageRect::CENTER); + else + setDefaultSize(380, 300, ImageRect::CENTER); + + mAnnounceCounter[BUY] = 0; + mAnnounceCounter[SELL] = 0; + + loadList(); + + mBuyShopItemList->setPriceCheck(false); + mSellShopItemList->setPriceCheck(false); + + mBuyScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mSellScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + + mBuyShopItemList->addSelectionListener(this); + mSellShopItemList->addSelectionListener(this); + + ContainerPlacer placer; + placer = getPlacer(0, 0); + + placer(0, 0, mBuyLabel, 8).setPadding(3); + placer(8, 0, mSellLabel, 8).setPadding(3); + placer(0, 1, mBuyScrollArea, 8, 5).setPadding(3); + placer(8, 1, mSellScrollArea, 8, 5).setPadding(3); + placer(0, 6, mBuyAddButton); + placer(1, 6, mBuyDeleteButton); + placer(3, 6, mBuyAnnounceButton); + placer(8, 6, mSellAddButton); + placer(9, 6, mSellDeleteButton); + placer(11, 6, mSellAnnounceButton); + placer(0, 7, mAnnounceLinks, 8); + placer(15, 7, mCloseButton); + + if (auctionManager && auctionManager->getEnableAuctionBot()) + { + mBuyAuctionButton = new Button(this, + // TRANSLATORS: shop window button + _("Auction"), "auction buy", this); + mSellAuctionButton = new Button(this, + // TRANSLATORS: shop window button + _("Auction"), "auction sell", this); + placer(4, 6, mBuyAuctionButton); + placer(12, 6, mSellAuctionButton); + } + else + { + mBuyAuctionButton = nullptr; + mSellAuctionButton = nullptr; + } + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + + center(); + loadWindowState(); + + instances.push_back(this); + setVisible(false); + enableVisibleSound(true); + + updateButtonsAndLabels(); +} + +ShopWindow::~ShopWindow() +{ + saveList(); + + delete mBuyShopItems; + mBuyShopItems = nullptr; + + delete mSellShopItems; + mSellShopItems = nullptr; + + instances.remove(this); +} + +void ShopWindow::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "close") + { + close(); + return; + } + else if (eventId == "yes") + { + startTrade(); + } + else if (eventId == "no") + { + mTradeNick.clear(); + } + else if (eventId == "ignore") + { + player_relations.ignoreTrade(mTradeNick); + mTradeNick.clear(); + } + else if (eventId == "delete buy" && mBuyShopItemList + && mBuyShopItemList->getSelected() >= 0) + { + mBuyShopItems->del(mBuyShopItemList->getSelected()); + if (isShopEmpty() && player_node) + player_node->updateStatus(); + } + else if (eventId == "delete sell" && mSellShopItemList + && mSellShopItemList->getSelected() >= 0) + { + mSellShopItems->del(mSellShopItemList->getSelected()); + if (isShopEmpty() && player_node) + player_node->updateStatus(); + } + else if (eventId == "announce buy" && mBuyShopItems + && mBuyShopItems->getNumberOfElements() > 0) + { + announce(mBuyShopItems, BUY); + } + else if (eventId == "announce sell" && mSellShopItems + && mSellShopItems->getNumberOfElements() > 0) + { + announce(mSellShopItems, SELL); + } + else if (eventId == "auction buy" && mBuyShopItems + && mBuyShopItems->getNumberOfElements() > 0) + { + Net::getChatHandler()->privateMessage("AuctionBot", "!pull4144 seek"); + } + else if (eventId == "auction sell" && mSellShopItems + && mSellShopItems->getNumberOfElements() > 0) + { + Net::getChatHandler()->privateMessage("AuctionBot", "!pull4144 offer"); + } + + if (mSelectedItem < 1) + return; + + const Inventory *const inv = PlayerInfo::getInventory(); + if (!inv) + return; + + // +++ need support for colors + Item *const item = inv->findItem(mSelectedItem, 0); + if (item) + { + if (eventId == "add buy") + { + ItemAmountWindow::showWindow(ItemAmountWindow::ShopBuyAdd, + this, item, sumAmount(item)); + } + else if (eventId == "add sell") + { + ItemAmountWindow::showWindow(ItemAmountWindow::ShopSellAdd, + this, item, sumAmount(item)); + } + } +} + +void ShopWindow::startTrade() +{ + if (!actorSpriteManager || !tradeWindow) + return; + + const Being *const being = actorSpriteManager->findBeingByName( + mTradeNick, Being::PLAYER); + tradeWindow->clear(); + if (mTradeMoney) + { + tradeWindow->addAutoMoney(mTradeNick, mTradeMoney); + } + else + { + tradeWindow->addAutoItem(mTradeNick, mTradeItem, + mTradeItem->getQuantity()); + } + Net::getTradeHandler()->request(being); + tradePartnerName = mTradeNick; + mTradeNick.clear(); +} + +void ShopWindow::valueChanged(const gcn::SelectionEvent &event A_UNUSED) +{ + updateButtonsAndLabels(); +} + +void ShopWindow::updateButtonsAndLabels() +{ + mBuyAddButton->setEnabled(mSelectedItem != -1); + mSellAddButton->setEnabled(mSelectedItem != -1); + mBuyDeleteButton->setEnabled( + mBuyShopItemList->getSelected() != -1 + && mBuyShopItems->getNumberOfElements() > 0); + mSellDeleteButton->setEnabled( + mSellShopItemList->getSelected() != -1 + && mSellShopItems->getNumberOfElements() > 0); +} + +void ShopWindow::setVisible(bool visible) +{ + Window::setVisible(visible); +} + +void ShopWindow::addBuyItem(const Item *const item, const int amount, + const int price) +{ + if (!mBuyShopItems || !item) + return; + const bool emp = isShopEmpty(); + mBuyShopItems->addItemNoDup(item->getId(), + item->getColor(), amount, price); + if (emp && player_node) + player_node->updateStatus(); + + updateButtonsAndLabels(); +} + +void ShopWindow::addSellItem(const Item *const item, const int amount, + const int price) +{ + if (!mBuyShopItems || !item) + return; + const bool emp = isShopEmpty(); + mSellShopItems->addItemNoDup(item->getId(), + item->getColor(), amount, price); + if (emp && player_node) + player_node->updateStatus(); + + updateButtonsAndLabels(); +} + +void ShopWindow::loadList() +{ + if (!mBuyShopItems || !mSellShopItems) + return; + + std::ifstream shopFile; + struct stat statbuf; + + mBuyShopItems->clear(); + mSellShopItems->clear(); + + const std::string shopListName = client->getServerConfigDirectory() + + "/shoplist.txt"; + + if (!stat(shopListName.c_str(), &statbuf) && S_ISREG(statbuf.st_mode)) + { + shopFile.open(shopListName.c_str(), std::ios::in); + if (!shopFile.is_open()) + { + shopFile.close(); + return; + } + char line[101]; + while (shopFile.getline(line, 100)) + { + std::string buf; + const std::string str = line; + if (!str.empty()) + { + std::vector tokens; + std::stringstream ss(str); + + while (ss >> buf) + tokens.push_back(atoi(buf.c_str())); + + if (tokens.size() == 5 && tokens[0]) + { + // +++ need impliment colors? + if (tokens[1] && tokens[2] && mBuyShopItems) + { + mBuyShopItems->addItem( + tokens[0], 1, tokens[1], tokens[2]); + } + if (tokens[3] && tokens[4] && mSellShopItems) + { + mSellShopItems->addItem( + tokens[0], 1, tokens[3], tokens[4]); + } + } + } + } + shopFile.close(); + } +} + +void ShopWindow::saveList() const +{ + if (!mBuyShopItems || !mSellShopItems) + return; + + std::ofstream shopFile; + const std::string shopListName = client->getServerConfigDirectory() + + "/shoplist.txt"; + std::map mapItems; + + shopFile.open(shopListName.c_str(), std::ios::binary); + if (!shopFile.is_open()) + { + logger->log1("Unable to open shoplist.txt for writing"); + return; + } + + std::vector items = mBuyShopItems->items(); + FOR_EACH (std::vector::const_iterator, it, items) + { + ShopItem *const item = *(it); + if (item) + mapItems[item->getId()] = item; + } + + items = mSellShopItems->items(); + FOR_EACH (std::vector::const_iterator, it, items) + { + if (!(*it)) + continue; + const ShopItem *const sellItem = *(it); + const ShopItem *const buyItem = mapItems[sellItem->getId()]; + + shopFile << sellItem->getId(); + if (buyItem) + { + shopFile << strprintf(" %d %d ", buyItem->getQuantity(), + buyItem->getPrice()); + mapItems.erase(sellItem->getId()); + } + else + { + shopFile << " 0 0 "; + } + + shopFile << strprintf("%d %d", sellItem->getQuantity(), + sellItem->getPrice()) << std::endl; + } + + for (std::map::const_iterator mapIt = mapItems.begin(), + mapIt_end = mapItems.end(); mapIt != mapIt_end; ++mapIt) + { + const ShopItem *const buyItem = (*mapIt).second; + if (buyItem) + { + shopFile << buyItem->getId(); + shopFile << strprintf(" %d %d ", buyItem->getQuantity(), + buyItem->getPrice()); + shopFile << "0 0" << std::endl; + } + } + + shopFile.close(); +} + +void ShopWindow::announce(ShopItems *const list, const int mode) +{ + if (!list) + return; + + std::string data("\302\202"); + if (mode == BUY) + data.append("Buy "); + else + data.append("Sell "); + + if (mAnnonceTime && (mAnnonceTime + (2 * 60) > cur_time + || mAnnonceTime > cur_time)) + { + return; + } + + mAnnonceTime = cur_time; + if (mBuyAnnounceButton) + mBuyAnnounceButton->setEnabled(false); + if (mSellAnnounceButton) + mSellAnnounceButton->setEnabled(false); + + std::vector items = list->items(); + + FOR_EACH (std::vector::const_iterator, it, items) + { + const ShopItem *const item = *(it); + if (item->getQuantity() > 1) + { + if (mAnnounceLinks->isSelected()) + { + data.append(strprintf("[@@%d|%s@@] (%dGP) %d, ", item->getId(), + item->getInfo().getName().c_str(), + item->getPrice(), item->getQuantity())); + } + else + { + data.append(strprintf("%s (%dGP) %d, ", + item->getInfo().getName().c_str(), + item->getPrice(), item->getQuantity())); + } + } + else + { + if (mAnnounceLinks->isSelected()) + { + data.append(strprintf("[@@%d|%s@@] (%dGP), ", item->getId(), + item->getInfo().getName().c_str(), item->getPrice())); + } + else + { + data.append(strprintf("%s (%dGP), ", + item->getInfo().getName().c_str(), item->getPrice())); + } + } + } + + Net::getChatHandler()->talk(data, GENERAL_CHANNEL); +} + +void ShopWindow::giveList(const std::string &nick, const int mode) +{ + if (!checkFloodCounter(mLastRequestTimeList)) + return; + + std::string data("\302\202"); + + ShopItems *list; + if (mode == BUY) + { + list = mBuyShopItems; + data.append("S1"); + } + else + { + list = mSellShopItems; + data.append("B1"); + } + if (!list) + return; + + const Inventory *const inv = PlayerInfo::getInventory(); + if (!inv) + return; + + std::vector items = list->items(); + + FOR_EACH (std::vector::const_iterator, it, items) + { + const ShopItem *const item = *(it); + if (!item) + continue; + + if (mode == SELL) + { + // +++ need support for colors + const Item *const item2 = inv->findItem(item->getId(), 0); + if (item2) + { + int amount = item->getQuantity(); + if (item2->getQuantity() < amount) + amount = item2->getQuantity(); + + if (amount) + { + data.append(strprintf("%s%s%s", + encodeStr(item->getId(), 2).c_str(), + encodeStr(item->getPrice(), 4).c_str(), + encodeStr(amount, 3).c_str())); + } + } + } + else + { + int amount = item->getQuantity(); + if (item->getPrice() * amount > PlayerInfo::getAttribute( + PlayerInfo::MONEY)) + { + amount = PlayerInfo::getAttribute(PlayerInfo::MONEY) + / item->getPrice(); + } + + if (amount > 0) + { + data.append(strprintf("%s%s%s", + encodeStr(item->getId(), 2).c_str(), + encodeStr(item->getPrice(), 4).c_str(), + encodeStr(amount, 3).c_str())); + } + } + } + sendMessage(nick, data, true); +} + +void ShopWindow::sendMessage(const std::string &nick, + std::string data, const bool random) +{ + if (!chatWindow) + return; + + if (random) + { + mRandCounter ++; + if (mRandCounter > 200) + mRandCounter = 0; + data.append(encodeStr(mRandCounter, 2)); + } + + if (config.getBoolValue("hideShopMessages")) + Net::getChatHandler()->privateMessage(nick, data); + else if (chatWindow) + chatWindow->addWhisper(nick, data, BY_PLAYER); +} + +void ShopWindow::showList(const std::string &nick, std::string data) const +{ + BuyDialog *buyDialog = nullptr; + SellDialog *sellDialog = nullptr; + if (data.find("B1") == 0) + { + data = data.substr(2); + buyDialog = new BuyDialog(nick); + } + else if (data.find("S1") == 0) + { + data = data.substr(2); + sellDialog = new SellDialog(nick); + } + else + { + return; + } + + const Inventory *const inv = PlayerInfo::getInventory(); + if (!inv) + return; + + if (buyDialog) + buyDialog->setMoney(PlayerInfo::getAttribute(PlayerInfo::MONEY)); + if (sellDialog) + sellDialog->setMoney(PlayerInfo::getAttribute(PlayerInfo::MONEY)); + + for (unsigned f = 0; f < data.length(); f += 9) + { + if (f + 9 > data.length()) + break; + + const int id = decodeStr(data.substr(f, 2)); + const int price = decodeStr(data.substr(f + 2, 4)); + int amount = decodeStr(data.substr(f + 6, 3)); + // +++ need impliment colors? + if (buyDialog && amount > 0) + buyDialog->addItem(id, 1, amount, price); + if (sellDialog) + { + // +++ need support for colors + const Item *const item = inv->findItem(id, 0); + if (item) + { + if (item->getQuantity() < amount) + amount = item->getQuantity(); + if (amount > 0) + sellDialog->addItem(id, 1, amount, price); + else + sellDialog->addItem(id, 1, -1, price); + } + } + } +} + +void ShopWindow::processRequest(const std::string &nick, std::string data, + const int mode) +{ + if (!player_node || !mTradeNick.empty() || PlayerInfo::isTrading() + || !actorSpriteManager + || !actorSpriteManager->findBeingByName(nick, Being::PLAYER)) + { + return; + } + + const Inventory *const inv = PlayerInfo::getInventory(); + if (!inv) + return; + + const size_t idx = data.find(" "); + if (idx == std::string::npos) + return; + + if (!checkFloodCounter(mLastRequestTimeItem)) + return; + + if (!mTradeNick.empty()) + { + sendMessage(nick, "error: player busy ", true); + return; + } + + data = data.substr(idx + 1); + + std::string part1; + std::string part2; + std::string part3; + std::stringstream ss(data); + std::string msg; + int id; + int price; + int amount; + + if (!(ss >> part1)) + return; + + if (!(ss >> part2)) + return; + + if (!(ss >> part3)) + return; + + id = atoi(part1.c_str()); + price = atoi(part2.c_str()); + amount = atoi(part3.c_str()); + + delete mTradeItem; + // +++ need impliment colors? + mTradeItem = new ShopItem(-1, id, 1, amount, price); + + if (mode == BUY) + { + // +++ need support for colors + const Item *const item2 = inv->findItem(mTradeItem->getId(), 0); + if (!item2 || item2->getQuantity() < amount + || !findShopItem(mTradeItem, SELL)) + { + sendMessage(nick, "error: Can't sell this item ", true); + return; + } + msg = "buy"; + mTradeMoney = 0; + } + else + { + if (!findShopItem(mTradeItem, BUY)) + { + sendMessage(nick, "error: Can't buy this item ", true); + return; + } + msg = "sell"; + mTradeMoney = mTradeItem->getPrice() * mTradeItem->getQuantity(); + } + + mTradeNick = nick; + + if (config.getBoolValue("autoShop")) + { + soundManager.playGuiSound(SOUND_TRADE); + startTrade(); + } + else + { + ConfirmDialog *const confirmDlg = new ConfirmDialog + // TRANSLATORS: shop window dialog + (_("Request for Trade"), strprintf(_("%s wants to %s %s do you " + "accept?"), nick.c_str(), msg.c_str(), + mTradeItem->getInfo().getName().c_str()), SOUND_REQUEST, true); + confirmDlg->addActionListener(this); + } +} + +void ShopWindow::updateTimes() +{ + BLOCK_START("ShopWindow::updateTimes") + if (mAnnonceTime + (2 * 60) < cur_time + || mAnnonceTime > cur_time) + { + mBuyAnnounceButton->setEnabled(true); + mSellAnnounceButton->setEnabled(true); + } + BLOCK_END("ShopWindow::updateTimes") +} + +bool ShopWindow::checkFloodCounter(int &counterTime) +{ + if (!counterTime || counterTime > cur_time) + counterTime = cur_time; + else if (counterTime + 10 > cur_time) + return false; + + counterTime = cur_time; + return true; +} + +bool ShopWindow::findShopItem(const ShopItem *const shopItem, + const int mode) const +{ + if (!shopItem) + return false; + + std::vector items; + if (mode == SELL) + { + if (!mSellShopItems) + return false; + items = mSellShopItems->items(); + } + else + { + if (!mBuyShopItems) + return false; + items = mBuyShopItems->items(); + } + + FOR_EACH (std::vector::const_iterator, it, items) + { + const ShopItem *const item = *(it); + if (!item) + continue; + + if (item->getId() == shopItem->getId() + && item->getPrice() == shopItem->getPrice() + && item->getQuantity() >= shopItem->getQuantity()) + { + return true; + } + } + return false; +} + +int ShopWindow::sumAmount(const Item *const shopItem) +{ + if (!player_node || !shopItem) + return 0; + + const Inventory *const inv = PlayerInfo::getInventory(); + if (!inv) + return 0; + int sum = 0; + + for (unsigned f = 0; f < inv->getSize(); f ++) + { + const Item *const item = inv->getItem(f); + if (item && item->getId() == shopItem->getId()) + sum += item->getQuantity(); + } + return sum; +} + +bool ShopWindow::isShopEmpty() const +{ + if (!mBuyShopItems || !mSellShopItems) + return true; + if (mBuyShopItems->empty() && mSellShopItems->empty()) + return true; + return false; +} diff --git a/src/gui/windows/shopwindow.h b/src/gui/windows/shopwindow.h new file mode 100644 index 000000000..6352f6721 --- /dev/null +++ b/src/gui/windows/shopwindow.h @@ -0,0 +1,179 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_SHOPWINDOW_H +#define GUI_SHOPWINDOW_H + +#include "gui/widgets/window.h" + +#include +#include + +class Button; +class CheckBox; +class Item; +class Label; +class ScrollArea; +class ShopItem; +class ShopItems; +class ShopListBox; + +/** + * The buy dialog. + * + * \ingroup Interface + */ +class ShopWindow final : public Window, + public gcn::ActionListener, + public gcn::SelectionListener +{ + public: + enum ShopMode + { + BUY = 0, + SELL = 1 + }; + + /** + * Constructor. + * + * @see Window::Window + */ + ShopWindow(); + + A_DELETE_COPY(ShopWindow) + + /** + * Destructor + */ + ~ShopWindow(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + /** + * Updates the labels according to the selected item. + */ + void valueChanged(const gcn::SelectionEvent &event) override; + + /** + * Updates the state of buttons and labels. + */ + void updateButtonsAndLabels(); + + /** + * Sets the visibility of this window. + */ + void setVisible(bool visible) override; + + /** + * Returns true if any instances exist. + */ + static bool isActive() A_WARN_UNUSED + { return !instances.empty(); } + + void setItemSelected(const int id) + { mSelectedItem = id; updateButtonsAndLabels(); } + + void addBuyItem(const Item *const item, const int amount, + const int price); + + void addSellItem(const Item *const item, const int amount, + const int price); + + void loadList(); + + void saveList() const; + + void announce(ShopItems *const list, const int mode); + + void giveList(const std::string &nick, const int mode); + + void setAcceptPlayer(const std::string &name) + { mAcceptPlayer = name; } + + const std::string &getAcceptPlayer() const A_WARN_UNUSED + { return mAcceptPlayer; } + + void sendMessage(const std::string &nick, std::string data, + const bool random = false); + + void showList(const std::string &nick, std::string data) const; + + void processRequest(const std::string &nick, std::string data, + const int mode); + + bool findShopItem(const ShopItem *const shopItem, + const int mode) const A_WARN_UNUSED; + + static int sumAmount(const Item *const shopItem) A_WARN_UNUSED; + + void updateTimes(); + + static bool checkFloodCounter(int &counterTime) A_WARN_UNUSED; + + bool isShopEmpty() const A_WARN_UNUSED; + + private: + void startTrade(); + + typedef std::list DialogList; + static DialogList instances; + + Button *mCloseButton; + + ShopItems *mBuyShopItems; + ShopItems *mSellShopItems; + + ShopListBox *mBuyShopItemList; + ShopListBox *mSellShopItemList; + ScrollArea *mBuyScrollArea; + ScrollArea *mSellScrollArea; + Label *mBuyLabel; + Label *mSellLabel; + Button *mBuyAddButton; + Button *mBuyDeleteButton; + Button *mBuyAnnounceButton; + Button *mBuyAuctionButton; + Button *mSellAddButton; + Button *mSellDeleteButton; + Button *mSellAnnounceButton; + Button *mSellAuctionButton; + CheckBox *mAnnounceLinks; + + int mSelectedItem; + int mAnnonceTime; + int mLastRequestTimeList; + int mLastRequestTimeItem; + int mRandCounter; + std::string mAcceptPlayer; + ShopItem *mTradeItem; + std::string mTradeNick; + int mTradeMoney; + int mAnnounceCounter[2]; +}; + +extern ShopWindow *shopWindow; + +#endif // GUI_SHOPWINDOW_H diff --git a/src/gui/windows/shortcutwindow.cpp b/src/gui/windows/shortcutwindow.cpp new file mode 100644 index 000000000..1ae74efb3 --- /dev/null +++ b/src/gui/windows/shortcutwindow.cpp @@ -0,0 +1,242 @@ +/* + * The ManaPlus Client + * Copyright (C) 2007-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/shortcutwindow.h" + +#include "gui/windows/setup.h" + +#include "gui/widgets/layout.h" +#include "gui/widgets/scrollarea.h" +#include "gui/widgets/shortcutcontainer.h" +#include "gui/widgets/tab.h" + +#include "debug.h" + +static const int SCROLL_PADDING = 0; + +int ShortcutWindow::mBoxesWidth = 0; + +class ShortcutTab final : public Tab +{ + public: + ShortcutTab(const Widget2 *const widget, + std::string name, ShortcutContainer *const content) : + Tab(widget), + mContent(content) + { + setCaption(name); + } + + A_DELETE_COPY(ShortcutTab) + + ShortcutContainer* mContent; +}; + +ShortcutWindow::ShortcutWindow(const std::string &title, + ShortcutContainer *const content, + const std::string &skinFile, + int width, int height) : + Window("Window", false, nullptr, skinFile), + mItems(content), + mScrollArea(new ScrollArea(mItems, false)), + mTabs(nullptr), + mPages() +{ + setWindowName(title); + setTitleBarHeight(getPadding() + getTitlePadding()); + + setShowTitle(false); + setResizable(true); + setDefaultVisible(false); + setSaveVisible(true); + + mDragOffsetX = 0; + mDragOffsetY = 0; + + content->setWidget2(this); + if (setupWindow) + setupWindow->registerWindowForReset(this); + + const int border = SCROLL_PADDING * 2 + getPadding() * 2; + setMinWidth(mItems->getBoxWidth() + border); + setMinHeight(mItems->getBoxHeight() + border); + setMaxWidth(mItems->getBoxWidth() * mItems->getMaxItems() + border); + setMaxHeight(mItems->getBoxHeight() * mItems->getMaxItems() + border); + + if (width == 0) + width = mItems->getBoxWidth() + border; + if (height == 0) + height = (mItems->getBoxHeight() * mItems->getMaxItems()) + border; + + setDefaultSize(width, height, ImageRect::LOWER_RIGHT); + + mBoxesWidth += mItems->getBoxWidth() + border; + + mScrollArea->setPosition(SCROLL_PADDING, SCROLL_PADDING); + mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + + place(0, 0, mScrollArea, 5, 5).setPadding(0); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + layout.setMargin(0); + + loadWindowState(); + enableVisibleSound(true); +} + +ShortcutWindow::ShortcutWindow(const std::string &title, + const std::string &skinFile, + const int width, const int height) : + Window("Window", false, nullptr, skinFile), + mItems(nullptr), + mScrollArea(nullptr), + mTabs(new TabbedArea(this)), + mPages() +{ + setWindowName(title); + setTitleBarHeight(getPadding() + getTitlePadding()); + setShowTitle(false); + setResizable(true); + setDefaultVisible(false); + setSaveVisible(true); + + mDragOffsetX = 0; + mDragOffsetY = 0; + + if (setupWindow) + setupWindow->registerWindowForReset(this); + + const int border = SCROLL_PADDING * 2 + getPadding() * 2; + + if (width && height) + setDefaultSize(width, height, ImageRect::LOWER_RIGHT); + + setMinWidth(32 + border); + setMinHeight(32 + border); + + place(0, 0, mTabs, 5, 5); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + layout.setMargin(0); + + loadWindowState(); + enableVisibleSound(true); +} + +ShortcutWindow::~ShortcutWindow() +{ + if (mTabs) + mTabs->removeAll(); + delete mTabs; + mTabs = nullptr; + delete mItems; + mItems = nullptr; +} + +void ShortcutWindow::addTab(const std::string &name, + ShortcutContainer *const content) +{ + ScrollArea *const scroll = new ScrollArea(content, false); + scroll->setPosition(SCROLL_PADDING, SCROLL_PADDING); + scroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + content->setWidget2(this); + Tab *const tab = new ShortcutTab(this, name, content); + mTabs->addTab(tab, scroll); + mPages.push_back(content); +} + +int ShortcutWindow::getTabIndex() const +{ + if (!mTabs) + return 0; + return mTabs->getSelectedTabIndex(); +} + +void ShortcutWindow::widgetHidden(const gcn::Event &event) +{ + if (mItems) + mItems->widgetHidden(event); + if (mTabs) + { + ScrollArea *const scroll = static_cast( + mTabs->getCurrentWidget()); + if (scroll) + { + ShortcutContainer *const content = static_cast( + scroll->getContent()); + + if (content) + content->widgetHidden(event); + } + } +} + +void ShortcutWindow::mousePressed(gcn::MouseEvent &event) +{ + Window::mousePressed(event); + + if (event.isConsumed()) + return; + + if (event.getButton() == gcn::MouseEvent::LEFT) + { + mDragOffsetX = event.getX(); + mDragOffsetY = event.getY(); + } +} + +void ShortcutWindow::mouseDragged(gcn::MouseEvent &event) +{ + Window::mouseDragged(event); + + if (event.isConsumed()) + return; + + if (canMove() && isMovable() && mMoved) + { + int newX = std::max(0, getX() + event.getX() - mDragOffsetX); + int newY = std::max(0, getY() + event.getY() - mDragOffsetY); + newX = std::min(mainGraphics->mWidth - getWidth(), newX); + newY = std::min(mainGraphics->mHeight - getHeight(), newY); + setPosition(newX, newY); + } +} + +void ShortcutWindow::widgetMoved(const gcn::Event& event) +{ + Window::widgetMoved(event); + if (mItems) + mItems->setRedraw(true); + FOR_EACH (std::vector::iterator, it, mPages) + (*it)->setRedraw(true); +} + +#ifdef USE_PROFILER +void ShortcutWindow::logicChildren() +{ + BLOCK_START("ShortcutWindow::logicChildren") + BasicContainer::logicChildren(); + BLOCK_END("ShortcutWindow::logicChildren") +} +#endif diff --git a/src/gui/windows/shortcutwindow.h b/src/gui/windows/shortcutwindow.h new file mode 100644 index 000000000..cc2ba97b0 --- /dev/null +++ b/src/gui/windows/shortcutwindow.h @@ -0,0 +1,90 @@ +/* + * The ManaPlus Client + * Copyright (C) 2007-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_SHORTCUTWINDOW_H +#define GUI_SHORTCUTWINDOW_H + +#include "gui/widgets/window.h" + +class ScrollArea; +class ShortcutContainer; +class TabbedArea; + +/** + * A window around a ShortcutContainer. + * + * \ingroup Interface + */ +class ShortcutWindow final : public Window +{ + public: + /** + * Constructor. + */ + ShortcutWindow(const std::string &title, + ShortcutContainer *const content, + const std::string &skinFile = "", + int width = 0, int height = 0); + + ShortcutWindow(const std::string &title, + const std::string &skinFile = "", + const int width = 0, const int height = 0); + + A_DELETE_COPY(ShortcutWindow) + + /** + * Destructor. + */ + ~ShortcutWindow(); + + void addTab(const std::string &name, ShortcutContainer *const content); + + int getTabIndex() const A_WARN_UNUSED; + + void widgetHidden(const gcn::Event &event) override; + + void widgetMoved(const gcn::Event& event) override; + + void mousePressed(gcn::MouseEvent &event) override; + + void mouseDragged(gcn::MouseEvent &event) override; + +#ifdef USE_PROFILER + void logicChildren(); +#endif + + private: + ShortcutWindow(); + ShortcutContainer *mItems; + + ScrollArea *mScrollArea; + TabbedArea *mTabs; + std::vector mPages; + + static int mBoxesWidth; +}; + +extern ShortcutWindow *itemShortcutWindow; +extern ShortcutWindow *emoteShortcutWindow; +extern ShortcutWindow *dropShortcutWindow; + +#endif // GUI_SHORTCUTWINDOW_H diff --git a/src/gui/windows/skilldialog.cpp b/src/gui/windows/skilldialog.cpp new file mode 100644 index 000000000..39cdc5d2f --- /dev/null +++ b/src/gui/windows/skilldialog.cpp @@ -0,0 +1,722 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/skilldialog.h" + +#include "configuration.h" +#include "dragdrop.h" +#include "effectmanager.h" +#include "itemshortcut.h" + +#include "being/localplayer.h" + +#include "gui/textpopup.h" +#include "gui/viewport.h" + +#include "gui/windows/setup.h" +#include "gui/windows/shortcutwindow.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/label.h" +#include "gui/widgets/listbox.h" +#include "gui/widgets/scrollarea.h" +#include "gui/widgets/skillmodel.h" +#include "gui/widgets/tab.h" +#include "gui/widgets/tabbedarea.h" + +#include "net/net.h" +#include "net/playerhandler.h" +#include "net/skillhandler.h" + +#include "utils/dtor.h" +#include "utils/gettext.h" + +#include + +#include "debug.h" + +class SkillListBox final : public ListBox +{ + public: + SkillListBox(const Widget2 *const widget, SkillModel *const model) : + ListBox(widget, model, "skilllistbox.xml"), + mModel(model), + mPopup(new TextPopup), + mHighlightColor(getThemeColor(Theme::HIGHLIGHT)), + mTextColor(getThemeColor(Theme::TEXT)), + mTextColor2(getThemeColor(Theme::TEXT_OUTLINE)), + mTextPadding(mSkin ? mSkin->getOption("textPadding", 34) : 34), + mSpacing(mSkin ? mSkin->getOption("spacing", 0) : 0), + mRowHeight(getFont()->getHeight() * 2 + mSpacing + 2 * mPadding), + mSkillClicked(false) + { + if (mRowHeight < 34) + mRowHeight = 34; + } + + A_DELETE_COPY(SkillListBox) + + ~SkillListBox() + { + delete mModel; + mModel = nullptr; + delete mPopup; + mPopup = nullptr; + } + + SkillInfo *getSelectedInfo() const + { + const int selected = getSelected(); + if (!mListModel || selected < 0 + || selected > mListModel->getNumberOfElements()) + { + return nullptr; + } + + return static_cast(mListModel)->getSkillAt(selected); + } + + void draw(gcn::Graphics *gcnGraphics) override + { + if (!mListModel) + return; + + SkillModel *const model = static_cast(mListModel); + updateAlpha(); + Graphics *const graphics = static_cast( + gcnGraphics); + + mHighlightColor.a = static_cast(mAlpha * 255.0F); + graphics->setColor(mHighlightColor); + + // Draw filled rectangle around the selected list element + if (mSelected >= 0) + { + graphics->fillRectangle(gcn::Rectangle(mPadding, getRowHeight() + * mSelected + mPadding, getWidth() - 2 * mPadding, + getRowHeight())); + } + + // Draw the list elements + graphics->setColorAll(mTextColor, mTextColor2); + gcn::Font *const font = getFont(); + const int space = font->getHeight() + mSpacing; + const int width2 = getWidth() - mPadding; + for (int i = 0, y = 1; + i < model->getNumberOfElements(); + ++i, y += getRowHeight()) + { + SkillInfo *const e = model->getSkillAt(i); + if (e) + { + const SkillData *const data = e->data; + const int yPad = y + mPadding; + const std::string &description = data->description; + graphics->drawImage(data->icon, mPadding, yPad); + font->drawString(graphics, data->name, mTextPadding, yPad); + if (!description.empty()) + { + font->drawString(graphics, description, + mTextPadding, yPad + space); + } + + if (e->skillLevelWidth < 0) + { + // Add one for padding + e->skillLevelWidth = font->getWidth(e->skillLevel) + 1; + } + + font->drawString(graphics, e->skillLevel, width2 + - e->skillLevelWidth, yPad); + } + } + } + + unsigned int getRowHeight() const override + { return mRowHeight; } + + const SkillInfo *getSkillByEvent(const gcn::MouseEvent &event) const + { + const int y = (event.getY() + mPadding) / getRowHeight(); + if (!mModel || y >= mModel->getNumberOfElements()) + return nullptr; + const SkillInfo *const skill = mModel->getSkillAt(y); + if (!skill) + return nullptr; + return skill; + } + + void mouseMoved(gcn::MouseEvent &event) override + { + ListBox::mouseMoved(event); + if (!viewport || !dragDrop.isEmpty()) + return; + + const SkillInfo *const skill = getSkillByEvent(event); + if (!skill) + return; + + mPopup->show(viewport->getMouseX(), viewport->getMouseY(), + skill->data->dispName, skill->data->description); + } + + void mouseDragged(gcn::MouseEvent &event) + { + if (event.getButton() == gcn::MouseEvent::LEFT) + { + if (dragDrop.isEmpty()) + { + if (mSkillClicked) + { + mSkillClicked = false; + const SkillInfo *const skill = getSkillByEvent(event); + if (!skill) + return; + dragDrop.dragSkill(skill, DRAGDROP_SOURCE_SKILLS); + dragDrop.setItem(skill->id + SKILL_MIN_ID); + } + ListBox::mouseDragged(event); + } + } + else + { + ListBox::mouseDragged(event); + } + } + + void mousePressed(gcn::MouseEvent &event) + { + ListBox::mousePressed(event); + if (event.getButton() == gcn::MouseEvent::LEFT) + { + const SkillInfo *const skill = getSkillByEvent(event); + if (!skill) + return; + mSkillClicked = true; + } + } + + void mouseReleased(gcn::MouseEvent &event) + { + ListBox::mouseReleased(event); + } + + void mouseExited(gcn::MouseEvent &event A_UNUSED) override + { + mPopup->hide(); + } + + private: + SkillModel *mModel; + TextPopup *mPopup; + gcn::Color mHighlightColor; + gcn::Color mTextColor; + gcn::Color mTextColor2; + int mTextPadding; + int mSpacing; + int mRowHeight; + bool mSkillClicked; +}; + +class SkillTab final : public Tab +{ + public: + SkillTab(const Widget2 *const widget, + const std::string &name, SkillListBox *const listBox) : + Tab(widget), + mListBox(listBox) + { + setCaption(name); + } + + A_DELETE_COPY(SkillTab) + + ~SkillTab() + { + delete mListBox; + mListBox = nullptr; + } + + SkillInfo *getSelectedInfo() const + { + if (mListBox) + return mListBox->getSelectedInfo(); + else + return nullptr; + } + + protected: + void setCurrent() override + { + if (skillDialog) + skillDialog->updateTabSelection(); + } + + private: + SkillListBox *mListBox; +}; + +SkillDialog::SkillDialog() : + // TRANSLATORS: skills dialog name + Window(_("Skills"), false, nullptr, "skills.xml"), + gcn::ActionListener(), + mSkills(), + mTabs(new TabbedArea(this)), + mDeleteTabs(), + mPointsLabel(new Label(this, "0")), + // TRANSLATORS: skills dialog button + mUseButton(new Button(this, _("Use"), "use", this)), + // TRANSLATORS: skills dialog button + mIncreaseButton(new Button(this, _("Up"), "inc", this)), + mDefaultModel(nullptr) +{ + setWindowName("Skills"); + setCloseButton(true); + setResizable(true); + setSaveVisible(true); + setStickyButtonLock(true); + setDefaultSize(windowContainer->getWidth() - 280, 30, 275, 425); + if (setupWindow) + setupWindow->registerWindowForReset(this); + + mUseButton->setEnabled(false); + mIncreaseButton->setEnabled(false); + + place(0, 0, mTabs, 5, 5); + place(0, 5, mPointsLabel, 4); + place(3, 5, mUseButton); + place(4, 5, mIncreaseButton); + + setLocationRelativeTo(getParent()); + loadWindowState(); + enableVisibleSound(true); +} + +SkillDialog::~SkillDialog() +{ + clearSkills(); +} + +void SkillDialog::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "inc") + { + const SkillTab *const tab = static_cast( + mTabs->getSelectedTab()); + if (tab) + { + if (const SkillInfo *const info = tab->getSelectedInfo()) + Net::getPlayerHandler()->increaseSkill(info->id); + } + } + else if (eventId == "sel") + { + const SkillTab *const tab = static_cast( + mTabs->getSelectedTab()); + if (tab) + { + if (const SkillInfo *const info = tab->getSelectedInfo()) + { + mUseButton->setEnabled(info->range > 0); + mIncreaseButton->setEnabled(info->id < SKILL_VAR_MIN_ID); + const int num = itemShortcutWindow->getTabIndex(); + if (num >= 0 && num < static_cast(SHORTCUT_TABS) + && itemShortcut[num]) + { + itemShortcut[num]->setItemSelected( + info->id + SKILL_MIN_ID); + } + } + else + { + mUseButton->setEnabled(false); + mIncreaseButton->setEnabled(false); + } + } + } + else if (eventId == "use") + { + const SkillTab *const tab = static_cast( + mTabs->getSelectedTab()); + if (tab) + { + const SkillInfo *const info = tab->getSelectedInfo(); + if (info && player_node && player_node->getTarget()) + { + const Being *const being = player_node->getTarget(); + if (being) + { + Net::getSkillHandler()->useBeing(info->level, + info->id, being->getId()); + } + } + } + } + else if (eventId == "close") + { + setVisible(false); + } +} + +std::string SkillDialog::update(const int id) +{ + const SkillMap::const_iterator i = mSkills.find(id); + + if (i != mSkills.end()) + { + SkillInfo *const info = i->second; + if (info) + { + info->update(); + return info->data->name; + } + } + + return std::string(); +} + +void SkillDialog::update() +{ + // TRANSLATORS: skills dialog label + mPointsLabel->setCaption(strprintf(_("Skill points available: %d"), + PlayerInfo::getAttribute(PlayerInfo::SKILL_POINTS))); + mPointsLabel->adjustSize(); + + FOR_EACH (SkillMap::const_iterator, it, mSkills) + { + if ((*it).second && (*it).second->modifiable) + (*it).second->update(); + } +} + +void SkillDialog::clearSkills() +{ + mTabs->removeAll(); + mDeleteTabs.clear(); + mDefaultModel = nullptr; + + delete_all(mSkills); + mSkills.clear(); +} + +void SkillDialog::loadSkills() +{ + clearSkills(); + + XML::Document doc(paths.getStringValue("skillsFile")); + XML::Document doc2(paths.getStringValue("skillsFile2")); + XmlNodePtr root = doc.rootNode(); + + int setCount = 0; + std::string setName; + ScrollArea *scroll; + SkillListBox *listbox; + SkillTab *tab; + + if (!root || !xmlNameEqual(root, "skills")) + root = doc2.rootNode(); + + if (!root || !xmlNameEqual(root, "skills")) + { + logger->log("Error loading skills"); + +#ifdef MANASERV_SUPPORT + if (Net::getNetworkType() != ServerInfo::MANASERV) +#endif + { + SkillModel *const model = new SkillModel(); + if (!mDefaultModel) + mDefaultModel = model; + + SkillInfo *const skill = new SkillInfo; + skill->id = 1; + // TRANSLATORS: skills dialog default skills tab + skill->data->name = _("basic"); + skill->data->description.clear(); + // TRANSLATORS: skills dialog default skill name + skill->data->dispName = _("basic, 1"); + skill->data->shortName = "bas"; + skill->data->setIcon(""); + skill->modifiable = true; + skill->visible = true; + skill->model = model; + skill->update(); + + model->addSkill(skill); + mSkills[1] = skill; + + model->updateVisibilities(); + + listbox = new SkillListBox(this, model); + listbox->setActionEventId("sel"); + listbox->addActionListener(this); + scroll = new ScrollArea(listbox, false); + scroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); + scroll->setVerticalScrollPolicy(ScrollArea::SHOW_ALWAYS); + + tab = new SkillTab(this, "Skills", listbox); + mDeleteTabs.push_back(tab); + + mTabs->addTab(tab, scroll); + + update(); + } + return; + } + + for_each_xml_child_node(set, root) + { + if (xmlNameEqual(set, "set")) + { + setCount++; + setName = XML::getProperty(set, "name", + // TRANSLATORS: skills dialog default skill tab + strprintf(_("Skill Set %d"), setCount)); + + SkillModel *const model = new SkillModel(); + if (!mDefaultModel) + mDefaultModel = model; + + for_each_xml_child_node(node, set) + { + if (xmlNameEqual(node, "skill")) + { + int id = XML::getIntProperty(node, "id", -1, -1, 1000000); + if (id == -1) + { + id = XML::getIntProperty(node, "var", -1, -1, 100000); + if (id == -1) + continue; + id += SKILL_VAR_MIN_ID; + } + + SkillInfo *skill = getSkill(id); + if (!skill) + { + skill = new SkillInfo; + skill->id = static_cast(id); + skill->modifiable = false; + skill->visible = false; + skill->model = model; + skill->update(); + model->addSkill(skill); + mSkills[id] = skill; + } + + std::string name = XML::langProperty(node, "name", + // TRANSLATORS: skills dialog. skill id + strprintf(_("Skill %d"), id)); + std::string icon = XML::getProperty(node, "icon", ""); + const int level = XML::getProperty(node, "level", 0); + SkillData *data = skill->getData(level); + if (!data) + data = new SkillData(); + + data->name = name; + data->setIcon(icon); + if (skill->id < SKILL_VAR_MIN_ID) + { + data->dispName = strprintf("%s, %u", + name.c_str(), skill->id); + } + else + { + data->dispName = strprintf("%s, (%u)", + name.c_str(), skill->id - SKILL_VAR_MIN_ID); + } + data->shortName = XML::langProperty(node, + "shortName", name.substr(0, 3)); + data->description = XML::langProperty( + node, "description", ""); + data->particle = XML::getProperty( + node, "particle", ""); + + data->soundHit.sound = XML::getProperty( + node, "soundHit", ""); + data->soundHit.delay = XML::getProperty( + node, "soundHitDelay", 0); + data->soundMiss.sound = XML::getProperty( + node, "soundMiss", ""); + data->soundMiss.delay = XML::getProperty( + node, "soundMissDelay", 0); + + skill->addData(level, data); + } + } + + model->updateVisibilities(); + + // possible leak listbox, scroll + listbox = new SkillListBox(this, model); + listbox->setActionEventId("sel"); + listbox->addActionListener(this); + scroll = new ScrollArea(listbox, false); + scroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); + scroll->setVerticalScrollPolicy(ScrollArea::SHOW_ALWAYS); + + tab = new SkillTab(this, setName, listbox); + mDeleteTabs.push_back(tab); + + mTabs->addTab(tab, scroll); + } + } + update(); +} + +bool SkillDialog::updateSkill(const int id, const int range, + const bool modifiable) +{ + const SkillMap::const_iterator it = mSkills.find(id); + + if (it != mSkills.end()) + { + SkillInfo *const info = it->second; + if (info) + { + info->modifiable = modifiable; + info->range = range; + info->update(); + } + return true; + } + return false; +} + +void SkillDialog::addSkill(const int id, const int level, const int range, + const bool modifiable) +{ + if (mDefaultModel) + { + SkillInfo *const skill = new SkillInfo; + skill->id = static_cast(id); + SkillData *const data = skill->data; + data->name = "Unknown skill Id: " + toString(id); + data->dispName = data->name; + data->description.clear(); + data->setIcon(""); + skill->modifiable = modifiable; + skill->visible = false; + skill->model = mDefaultModel; + skill->level = level; + // TRANSLATORS: skills dialog. skill level + skill->skillLevel = strprintf(_("Lvl: %d"), level); + skill->range = range; + skill->update(); + + mDefaultModel->addSkill(skill); + + mSkills[id] = skill; + mDefaultModel->updateVisibilities(); + } +} + +SkillInfo* SkillDialog::getSkill(const int id) const +{ + SkillMap::const_iterator it = mSkills.find(id); + if (it != mSkills.end()) + return (*it).second; + return nullptr; +} + +SkillInfo* SkillDialog::getSkillByItem(const int itemId) const +{ + SkillMap::const_iterator it = mSkills.find(itemId - SKILL_MIN_ID); + if (it != mSkills.end()) + return (*it).second; + return nullptr; +} + +void SkillDialog::widgetResized(const gcn::Event &event) +{ + Window::widgetResized(event); + + if (mTabs) + mTabs->adjustSize(); +} + +void SkillDialog::useItem(const int itemId) const +{ + const std::map::const_iterator + it = mSkills.find(itemId - SKILL_MIN_ID); + if (it == mSkills.end()) + return; + + const SkillInfo *const info = (*it).second; + if (info && player_node && player_node->getTarget()) + { + const Being *const being = player_node->getTarget(); + if (being) + { + Net::getSkillHandler()->useBeing(info->level, + info->id, being->getId()); + } + } +} + +void SkillDialog::updateTabSelection() +{ + const SkillTab *const tab = static_cast( + mTabs->getSelectedTab()); + if (tab) + { + if (const SkillInfo *const info = tab->getSelectedInfo()) + { + mUseButton->setEnabled(info->range > 0); + mIncreaseButton->setEnabled(info->id < SKILL_VAR_MIN_ID); + } + else + { + mUseButton->setEnabled(false); + } + } +} + +void SkillDialog::updateQuest(const int var, const int val) +{ + const int id = var + SKILL_VAR_MIN_ID; + const SkillMap::const_iterator it = mSkills.find(id); + + if (it != mSkills.end()) + { + SkillInfo *const info = it->second; + if (info) + { + PlayerInfo::setSkillLevel(id, val); + info->level = val; + info->update(); + } + } +} + +void SkillDialog::playUpdateEffect(const int id) const +{ + const int effectId = paths.getIntValue("skillLevelUpEffectId"); + if (!effectManager || effectId == -1) + return; + const SkillMap::const_iterator it = mSkills.find(id); + if (it != mSkills.end()) + { + if (it->second) + effectManager->trigger(effectId, player_node); + } +} diff --git a/src/gui/windows/skilldialog.h b/src/gui/windows/skilldialog.h new file mode 100644 index 000000000..9715a3bf3 --- /dev/null +++ b/src/gui/windows/skilldialog.h @@ -0,0 +1,109 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_SKILLDIALOG_H +#define GUI_SKILLDIALOG_H + +#include "gui/widgets/window.h" + +#include + +const int SKILL_MIN_ID = 200000; +const unsigned int SKILL_VAR_MIN_ID = 1000000; + +class Button; +class Label; +class SkillModel; +class Tab; +class TabbedArea; + +struct SkillInfo; + +/** + * The skill dialog. + * + * \ingroup Interface + */ +class SkillDialog final : public Window, public gcn::ActionListener +{ + public: + SkillDialog(); + + A_DELETE_COPY(SkillDialog) + + ~SkillDialog(); + + /** + * Called when receiving actions from widget. + */ + void action(const gcn::ActionEvent &event) override; + + /** + * Update the given skill's display + */ + std::string update(const int id); + + /** + * Update other parts of the display + */ + void update(); + + void clearSkills(); + + void loadSkills(); + + bool updateSkill(const int id, const int range, const bool modifiable); + + void addSkill(const int id, const int level, const int range, + const bool modifiable); + + SkillInfo* getSkill(const int id) const A_WARN_UNUSED; + + SkillInfo* getSkillByItem(const int itemId) const A_WARN_UNUSED; + + bool hasSkills() const A_WARN_UNUSED + { return !mSkills.empty(); } + + void widgetResized(const gcn::Event &event) override; + + void useItem(const int itemId) const; + + void updateTabSelection(); + + void updateQuest(const int var, const int val); + + void playUpdateEffect(const int id) const; + + private: + typedef std::map SkillMap; + SkillMap mSkills; + TabbedArea *mTabs; + std::list mDeleteTabs; + Label *mPointsLabel; + Button *mUseButton; + Button *mIncreaseButton; + SkillModel *mDefaultModel; +}; + +extern SkillDialog *skillDialog; + +#endif // GUI_SKILLDIALOG_H diff --git a/src/gui/windows/socialwindow.cpp b/src/gui/windows/socialwindow.cpp new file mode 100644 index 000000000..687b1af69 --- /dev/null +++ b/src/gui/windows/socialwindow.cpp @@ -0,0 +1,1895 @@ +/* + * The ManaPlus Client + * Copyright (C) 2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/socialwindow.h" + +#include "actorspritemanager.h" +#include "configuration.h" +#include "guild.h" +#include "guildmanager.h" +#include "maplayer.h" +#include "party.h" + +#include "being/localplayer.h" +#include "being/playerrelations.h" + +#include "input/keyboardconfig.h" + +#include "gui/windows/confirmdialog.h" +#include "gui/windows/okdialog.h" +#include "gui/windows/setup.h" +#include "gui/windows/textdialog.h" +#include "gui/windows/whoisonline.h" + +#include "gui/windows/outfitwindow.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/browserbox.h" +#include "gui/widgets/chattab.h" +#include "gui/widgets/label.h" +#include "gui/widgets/popup.h" +#include "gui/widgets/scrollarea.h" + +#include "net/net.h" +#include "net/guildhandler.h" +#include "net/partyhandler.h" + +#include "utils/gettext.h" + +#include "debug.h" + +extern unsigned int tmwServerVersion; + +namespace +{ + static class SortFriendsFunctor final + { + public: + bool operator() (const Avatar *const m1, + const Avatar *const m2) const + { + if (!m1 || !m2) + return false; + + if (m1->getOnline() != m2->getOnline()) + return m1->getOnline() > m2->getOnline(); + + if (m1->getName() != m2->getName()) + { + std::string s1 = m1->getName(); + std::string s2 = m2->getName(); + toLower(s1); + toLower(s2); + return s1 < s2; + } + return false; + } + } friendSorter; +} // namespace + +class SocialTab : public Tab +{ +public: + A_DELETE_COPY(SocialTab) + + virtual void invite() + { + } + + virtual void leave() + { + } + + virtual void updateList() + { + } + + virtual void updateAvatar(const std::string &name A_UNUSED) + { + } + + virtual void resetDamage(const std::string &name A_UNUSED) + { + } + + virtual void selectIndex(const unsigned num A_UNUSED) + { } + +protected: + friend class SocialWindow; + + explicit SocialTab(const Widget2 *const widget): + Tab(widget), + mInviteDialog(nullptr), + mConfirmDialog(nullptr), + mScroll(nullptr), + mList(nullptr), + mCounterString() + { + } + + virtual ~SocialTab() + { + // Cleanup dialogs + if (mInviteDialog) + { + mInviteDialog->close(); + mInviteDialog->scheduleDelete(); + mInviteDialog = nullptr; + } + + if (mConfirmDialog) + { + mConfirmDialog->close(); + mConfirmDialog->scheduleDelete(); + mConfirmDialog = nullptr; + } + } + + void setCurrent() override + { + updateCounter(); + } + + void updateCounter() const + { + if (socialWindow) + socialWindow->setCounter(this, mCounterString); + } + + virtual void buildCounter(const int online A_UNUSED = 0, + const int total A_UNUSED = 0) + { + } + + TextDialog *mInviteDialog; + ConfirmDialog *mConfirmDialog; + ScrollArea *mScroll; + AvatarListBox *mList; + std::string mCounterString; +}; + +class SocialGuildTab final : public SocialTab, public gcn::ActionListener +{ +public: + SocialGuildTab(const Widget2 *const widget, + Guild *const guild, const bool showBackground) : + SocialTab(widget), + gcn::ActionListener(), + mGuild(guild) + { + // TRANSLATORS: tab in social window + setCaption(_("Guild")); + + setTabColor(&getThemeColor(Theme::GUILD_SOCIAL_TAB), + &getThemeColor(Theme::GUILD_SOCIAL_TAB_OUTLINE)); + setHighlightedTabColor(&getThemeColor( + Theme::GUILD_SOCIAL_TAB_HIGHLIGHTED), &getThemeColor( + Theme::GUILD_SOCIAL_TAB_HIGHLIGHTED_OUTLINE)); + setSelectedTabColor(&getThemeColor(Theme::GUILD_SOCIAL_TAB_SELECTED), + &getThemeColor(Theme::GUILD_SOCIAL_TAB_SELECTED_OUTLINE)); + + mList = new AvatarListBox(this, guild); + mScroll = new ScrollArea(mList, showBackground, + "social_background.xml"); + + mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); + mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); + } + + A_DELETE_COPY(SocialGuildTab) + + ~SocialGuildTab() + { + delete mList; + mList = nullptr; + delete mScroll; + mScroll = nullptr; + } + + void action(const gcn::ActionEvent &event) override + { + const std::string &eventId = event.getId(); + if (eventId == "do invite") + { + const std::string name = mInviteDialog->getText(); + Net::getGuildHandler()->invite(mGuild->getId(), name); + + if (localChatTab) + { + localChatTab->chatLog(strprintf( + // TRANSLATORS: chat message + _("Invited user %s to guild %s."), + name.c_str(), mGuild->getName().c_str()), BY_SERVER); + } + mInviteDialog = nullptr; + } + else if (eventId == "~do invite") + { + mInviteDialog = nullptr; + } + else if (eventId == "yes") + { + Net::getGuildHandler()->leave(mGuild->getId()); + if (localChatTab) + { + // TRANSLATORS: chat message + localChatTab->chatLog(strprintf(_("Guild %s quit requested."), + mGuild->getName().c_str()), BY_SERVER); + } + mConfirmDialog = nullptr; + } + else if (eventId == "~yes") + { + mConfirmDialog = nullptr; + } + } + + void invite() override + { + // TRANSLATORS: guild invite message + mInviteDialog = new TextDialog(_("Member Invite to Guild"), + // TRANSLATORS: guild invite message + strprintf(_("Who would you like to invite to guild %s?"), + mGuild->getName().c_str()), socialWindow); + mInviteDialog->setActionEventId("do invite"); + mInviteDialog->addActionListener(this); + } + + void leave() override + { + // TRANSLATORS: guild leave message + mConfirmDialog = new ConfirmDialog(_("Leave Guild?"), + // TRANSLATORS: guild leave message + strprintf(_("Are you sure you want to leave guild %s?"), + mGuild->getName().c_str()), SOUND_REQUEST, socialWindow); + + mConfirmDialog->addActionListener(this); + } + + void buildCounter(const int online0, const int total0) + { + if (online0 || total0) + { + // TRANSLATORS: social window label + mCounterString = strprintf(_("Members: %u/%u"), online0, total0); + } + else + { + if (!player_node) + return; + + const Guild *const guild = player_node->getGuild(); + if (!guild) + return; + + const Guild::MemberList *const members = guild->getMembers(); + int online = 0; + int total = 0; + FOR_EACHP (Guild::MemberList::const_iterator, it, members) + { + if ((*it)->getOnline()) + online ++; + total ++; + } + + // TRANSLATORS: social window label + mCounterString = strprintf(_("Players: %u/%u"), online, total); + } + updateCounter(); + } + +private: + Guild *mGuild; +}; + +class SocialGuildTab2 final : public SocialTab, public gcn::ActionListener +{ +public: + SocialGuildTab2(const Widget2 *const widget, Guild *const guild, + const bool showBackground) : + SocialTab(widget), + gcn::ActionListener() + { + // TRANSLATORS: tab in social window + setCaption(_("Guild")); + + setTabColor(&getThemeColor(Theme::GUILD_SOCIAL_TAB), + &getThemeColor(Theme::GUILD_SOCIAL_TAB_OUTLINE)); + setHighlightedTabColor(&getThemeColor( + Theme::GUILD_SOCIAL_TAB_HIGHLIGHTED), &getThemeColor( + Theme::GUILD_SOCIAL_TAB_HIGHLIGHTED_OUTLINE)); + setSelectedTabColor(&getThemeColor(Theme::GUILD_SOCIAL_TAB_SELECTED), + &getThemeColor(Theme::GUILD_SOCIAL_TAB_SELECTED_OUTLINE)); + + mList = new AvatarListBox(this, guild); + mScroll = new ScrollArea(mList, showBackground, + "social_background.xml"); + + mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); + mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); + } + + A_DELETE_COPY(SocialGuildTab2) + + ~SocialGuildTab2() + { + delete mList; + mList = nullptr; + delete mScroll; + mScroll = nullptr; + } + + void action(const gcn::ActionEvent &event A_UNUSED) override + { + } + + void buildCounter(const int online0 A_UNUSED, const int total0 A_UNUSED) + { + if (!player_node) + return; + + const Guild *const guild = player_node->getGuild(); + if (!guild) + return; + + const Guild::MemberList *const members = guild->getMembers(); + int online = 0; + int total = 0; + FOR_EACHP (Guild::MemberList::const_iterator, it, members) + { + if ((*it)->getOnline()) + online ++; + total ++; + } + + // TRANSLATORS: social window label + mCounterString = strprintf(_("Players: %u/%u"), online, total); + updateCounter(); + } +}; + +class SocialPartyTab final : public SocialTab, public gcn::ActionListener +{ +public: + SocialPartyTab(const Widget2 *const widget, + Party *const party, const bool showBackground) : + SocialTab(widget), + gcn::ActionListener(), + mParty(party) + { + // TRANSLATORS: tab in social window + setCaption(_("Party")); + + setTabColor(&getThemeColor(Theme::PARTY_SOCIAL_TAB), + &getThemeColor(Theme::PARTY_SOCIAL_TAB_OUTLINE)); + setHighlightedTabColor(&getThemeColor( + Theme::PARTY_SOCIAL_TAB_HIGHLIGHTED), &getThemeColor( + Theme::PARTY_SOCIAL_TAB_HIGHLIGHTED_OUTLINE)); + setSelectedTabColor(&getThemeColor(Theme::PARTY_SOCIAL_TAB_SELECTED), + &getThemeColor(Theme::PARTY_SOCIAL_TAB_SELECTED_OUTLINE)); + + mList = new AvatarListBox(this, party); + mScroll = new ScrollArea(mList, showBackground, + "social_background.xml"); + + mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); + mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); + } + + A_DELETE_COPY(SocialPartyTab) + + ~SocialPartyTab() + { + delete mList; + mList = nullptr; + delete mScroll; + mScroll = nullptr; + } + + void action(const gcn::ActionEvent &event) override + { + const std::string &eventId = event.getId(); + if (eventId == "do invite") + { + const std::string name = mInviteDialog->getText(); + Net::getPartyHandler()->invite(name); + + if (localChatTab) + { + // TRANSLATORS: chat message + localChatTab->chatLog(strprintf(_("Invited user %s to party."), + name.c_str()), BY_SERVER); + } + mInviteDialog = nullptr; + } + else if (eventId == "~do invite") + { + mInviteDialog = nullptr; + } + else if (eventId == "yes") + { + Net::getPartyHandler()->leave(); + if (localChatTab) + { + // TRANSLATORS: tab in social window + localChatTab->chatLog(strprintf(_("Party %s quit requested."), + mParty->getName().c_str()), BY_SERVER); + } + mConfirmDialog = nullptr; + } + else if (eventId == "~yes") + { + mConfirmDialog = nullptr; + } + } + + void invite() override + { + // TRANSLATORS: party invite message + mInviteDialog = new TextDialog(_("Member Invite to Party"), + // TRANSLATORS: party invite message + strprintf(_("Who would you like to invite to party %s?"), + mParty->getName().c_str()), socialWindow); + mInviteDialog->setActionEventId("do invite"); + mInviteDialog->addActionListener(this); + } + + void leave() override + { + // TRANSLATORS: party leave message + mConfirmDialog = new ConfirmDialog(_("Leave Party?"), + // TRANSLATORS: party leave message + strprintf(_("Are you sure you want to leave party %s?"), + mParty->getName().c_str()), SOUND_REQUEST, socialWindow); + + mConfirmDialog->addActionListener(this); + } + + void buildCounter(const int online0 A_UNUSED, const int total0 A_UNUSED) + { + if (!player_node) + return; + + const Party *const party = player_node->getParty(); + if (!party) + return; + + const Party::MemberList *const members = party->getMembers(); + int online = 0; + int total = 0; + FOR_EACHP (Party::MemberList::const_iterator, it, members) + { + if ((*it)->getOnline()) + online ++; + total ++; + } + + // TRANSLATORS: social window label + mCounterString = strprintf(_("Players: %u/%u"), online, total); + updateCounter(); + } + +private: + Party *mParty; +}; + +class BeingsListModal final : public AvatarListModel +{ +public: + BeingsListModal() : + AvatarListModel(), + mMembers() + { + } + + A_DELETE_COPY(BeingsListModal) + + ~BeingsListModal() + { + delete_all(mMembers); + mMembers.clear(); + } + + std::vector *getMembers() + { + return &mMembers; + } + + Avatar *getAvatarAt(int index) override + { + return mMembers[index]; + } + + int getNumberOfElements() override + { + return static_cast(mMembers.size()); + } + + std::vector mMembers; +}; + +class SocialPlayersTab final : public SocialTab +{ +public: + SocialPlayersTab(const Widget2 *const widget, + std::string name, const bool showBackground) : + SocialTab(widget), + mBeings(new BeingsListModal) + { + mList = new AvatarListBox(this, mBeings); + mScroll = new ScrollArea(mList, showBackground, + "social_background.xml"); + + mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); + mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); + + updateList(); + setCaption(name); + } + + A_DELETE_COPY(SocialPlayersTab) + + ~SocialPlayersTab() + { + delete mList; + mList = nullptr; + delete mScroll; + mScroll = nullptr; + delete mBeings; + mBeings = nullptr; + } + + void updateList() override + { + getPlayersAvatars(); + } + + void updateAvatar(const std::string &name) override + { + if (!actorSpriteManager) + return; + + Avatar *const avatar = findAvatarbyName(name); + if (!avatar) + return; + if (Party::getParty(1)) + { + const PartyMember *const pm = Party::getParty(1)->getMember(name); + if (pm && pm->getMaxHp() > 0) + { + avatar->setMaxHp(pm->getMaxHp()); + avatar->setHp(pm->getHp()); + } + } + const Being *const being = actorSpriteManager->findBeingByName( + name, Being::PLAYER); + if (being) + { + avatar->setDamageHp(being->getDamageTaken()); + avatar->setLevel(being->getLevel()); + avatar->setGender(being->getGender()); + avatar->setIp(being->getIp()); + } + } + + void resetDamage(const std::string &name) override + { + if (!actorSpriteManager) + return; + + Avatar *const avatar = findAvatarbyName(name); + if (!avatar) + return; + avatar->setDamageHp(0); + Being *const being = actorSpriteManager->findBeingByName( + name, Being::PLAYER); + + if (being) + being->setDamageTaken(0); + } + + Avatar* findAvatarbyName(std::string name) + { + std::vector *const avatars = mBeings->getMembers(); + if (!avatars) + return nullptr; + + Avatar *ava = nullptr; + std::vector::const_iterator i = avatars->begin(); + const std::vector::const_iterator i_end = avatars->end(); + while (i != i_end) + { + ava = (*i); + if (ava && ava->getName() == name) + return ava; + ++i; + } + ava = new Avatar(name); + ava->setOnline(true); + avatars->push_back(ava); + return ava; + } + + void getPlayersAvatars() + { + std::vector *const avatars = mBeings->getMembers(); + if (!avatars) + return; + + if (actorSpriteManager) + { + StringVect names; + actorSpriteManager->getPlayerNames(names, false); + + std::vector::iterator ai = avatars->begin(); + while (ai != avatars->end()) + { + bool finded = false; + const Avatar *const ava = (*ai); + if (!ava) + break; + + StringVectCIter i = names.begin(); + const StringVectCIter i_end = names.end(); + while (i != i_end) + { + if (ava->getName() == (*i) && (*i) != "") + { + finded = true; + break; + } + ++i; + } + + if (!finded) + { + delete *ai; + ai = avatars->erase(ai); + } + else + { + ++ai; + } + } + + StringVectCIter i = names.begin(); + const StringVectCIter i_end = names.end(); + + while (i != i_end) + { + if ((*i) != "") + updateAvatar(*i); + ++i; + } + } + // TRANSLATORS: social window label + mCounterString = strprintf(_("Visible players: %d"), + static_cast(avatars->size())); + updateCounter(); + } + +private: + BeingsListModal *mBeings; +}; + + +class SocialNavigationTab final : public SocialTab +{ +public: + SocialNavigationTab(const Widget2 *const widget, + const bool showBackground) : + SocialTab(widget), + mBeings(new BeingsListModal) + { + mList = new AvatarListBox(this, mBeings); + mScroll = new ScrollArea(mList, showBackground, + "social_background.xml"); + + mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); + mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); + + // TRANSLATORS: Navigation tab name in social window. Should be small + setCaption(_("Nav")); + } + + A_DELETE_COPY(SocialNavigationTab) + + ~SocialNavigationTab() + { + delete mList; + mList = nullptr; + delete mScroll; + mScroll = nullptr; + delete mBeings; + mBeings = nullptr; + } + + void updateList() override + { + if (!socialWindow || !player_node) + return; + + const Map *const map = socialWindow->getMap(); + if (!map || map->empty()) + return; + + if (socialWindow->getProcessedPortals()) + return; + + std::vector *const avatars = mBeings->getMembers(); + std::vector portals = map->getPortals(); + + std::vector::const_iterator i = portals.begin(); + const SpecialLayer *const specialLayer = map->getSpecialLayer(); + + std::vector::iterator ia = avatars->begin(); + + while (ia != avatars->end()) + { + delete *ia; + ++ ia; + } + + avatars->clear(); + + int online = 0; + int total = 0; + + int idx = 0; + while (i != portals.end()) + { + MapItem *portal = *i; + if (!portal) + continue; + + const int x = portal->getX(); + const int y = portal->getY(); + + const std::string name = strprintf("%s [%d %d]", + portal->getComment().c_str(), x, y); + + Avatar *const ava = new Avatar(name); + if (player_node) + ava->setOnline(player_node->isReachable(x, y, true)); + else + ava->setOnline(false); + ava->setLevel(-1); + ava->setType(portal->getType()); + ava->setX(x); + ava->setY(y); + avatars->push_back(ava); + + if (ava->getOnline()) + online ++; + total ++; + + if (config.getBoolValue("drawHotKeys") && idx < 80 && outfitWindow) + { + Being *const being = actorSpriteManager + ->findPortalByTile(x, y); + if (being) + { + being->setName(keyboard.getKeyShortString( + outfitWindow->keyName(idx))); + } + + if (specialLayer) + { + portal = specialLayer->getTile(ava->getX(), ava->getY()); + if (portal) + { + portal->setName(keyboard.getKeyShortString( + outfitWindow->keyName(idx))); + } + } + } + + ++i; + idx ++; + } + if (socialWindow) + socialWindow->setProcessedPortals(true); + + // TRANSLATORS: social window label + mCounterString = strprintf(_("Portals: %u/%u"), online, total); + updateCounter(); + } + + + void selectIndex(const unsigned num) override + { + if (!player_node) + return; + + std::vector *const avatars = mBeings->getMembers(); + if (!avatars || avatars->size() <= num) + return; + + const Avatar *const ava = avatars->at(num); + if (ava && player_node) + player_node->navigateTo(ava->getX(), ava->getY()); + } + + void updateNames() + { + if (!socialWindow) + return; + + std::vector *const avatars = mBeings->getMembers(); + if (!avatars) + return; + + const Map *const map = socialWindow->getMap(); + if (!map) + return; + + std::vector::const_iterator i = avatars->begin(); + const std::vector::const_iterator i_end = avatars->end(); + while (i != i_end) + { + Avatar *const ava = *i; + if (!ava) + break; + + const MapItem *const item = map->findPortalXY( + ava->getX(), ava->getY()); + if (item) + { + const std::string name = strprintf("%s [%d %d]", + item->getComment().c_str(), item->getX(), item->getY()); + ava->setName(name); + ava->setOriginalName(name); + } + + ++i; + } + } + + int getPortalIndex(const int x, const int y) + { + if (!socialWindow) + return -1; + + std::vector *const avatars = mBeings->getMembers(); + if (!avatars) + return -1; + + const Map *const map = socialWindow->getMap(); + if (!map) + return 01; + + std::vector::const_iterator i = avatars->begin(); + const std::vector::const_iterator i_end = avatars->end(); + unsigned num = 0; + while (i != i_end) + { + const Avatar *const ava = *i; + if (!ava) + break; + + if (ava->getX() == x && ava->getY() == y) + return num; + + ++i; + num ++; + } + return -1; + } + + void addPortal(const int x, const int y) + { + if (!socialWindow || !player_node) + return; + + const Map *const map = socialWindow->getMap(); + if (!map) + return; + + std::vector *const avatars = mBeings->getMembers(); + + if (!avatars) + return; + + const MapItem *const portal = map->findPortalXY(x, y); + if (!portal) + return; + + const std::string name = strprintf("%s [%d %d]", + portal->getComment().c_str(), x, y); + + Avatar *const ava = new Avatar(name); + if (player_node) + ava->setOnline(player_node->isReachable(x, y, true)); + else + ava->setOnline(false); + ava->setLevel(-1); + ava->setType(portal->getType()); + ava->setX(x); + ava->setY(y); + avatars->push_back(ava); + } + + void removePortal(const int x, const int y) + { + if (!socialWindow || !player_node) + return; + + const Map *const map = socialWindow->getMap(); + if (!map) + return; + + std::vector *const avatars = mBeings->getMembers(); + + if (!avatars) + return; + + std::vector::iterator i = avatars->begin(); + const std::vector::iterator i_end = avatars->end(); + + while (i != i_end) + { + Avatar *ava = (*i); + + if (!ava) + break; + + if (ava->getX() == x && ava->getY() == y) + { + delete ava; + avatars->erase(i); + return; + } + + ++ i; + } + } + +private: + BeingsListModal *mBeings; +}; + + +#define addAvatars(mob, str, type) \ +{\ + ava = new Avatar(str);\ + ava->setOnline(false);\ + ava->setLevel(-1);\ + ava->setType(MapItem::SEPARATOR);\ + ava->setX(0);\ + ava->setY(0);\ + avatars->push_back(ava);\ + mobs = actorSpriteManager->get##mob##s();\ + i = mobs.begin();\ + i_end = mobs.end();\ + while (i != i_end)\ + {\ + std::string name;\ + int level = -1;\ + if (*i == "")\ + {\ + name = _("(default)");\ + level = 0;\ + }\ + else\ + {\ + name = *i;\ + }\ + ava = new Avatar(name);\ + ava->setOnline(true);\ + ava->setLevel(level);\ + ava->setType(MapItem::type);\ + ava->setX(0);\ + ava->setY(0);\ + avatars->push_back(ava);\ + ++ i;\ + }\ +} + +#define updateAtkListStart() \ + if (!socialWindow || !player_node || !actorSpriteManager)\ + return;\ + std::vector *const avatars = mBeings->getMembers();\ + std::vector::iterator ia = avatars->begin();\ + while (ia != avatars->end())\ + {\ + delete *ia;\ + ++ ia;\ + }\ + avatars->clear();\ + Avatar *ava;\ + std::list mobs;\ + std::list::const_iterator i;\ + std::list::const_iterator i_end; + +class SocialAttackTab final : public SocialTab +{ +public: + SocialAttackTab(const Widget2 *const widget, + const bool showBackground) : + SocialTab(widget), + mBeings(new BeingsListModal) + { + mList = new AvatarListBox(this, mBeings); + mScroll = new ScrollArea(mList, showBackground, + "social_background.xml"); + + mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); + mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); + + // TRANSLATORS: Attack filter tab name in social window. Should be small + setCaption(_("Atk")); + } + + A_DELETE_COPY(SocialAttackTab) + + ~SocialAttackTab() + { + delete mList; + mList = nullptr; + delete mScroll; + mScroll = nullptr; + delete mBeings; + mBeings = nullptr; + } + + void updateList() override + { + updateAtkListStart(); + // TRANSLATORS: mobs group name in social window + addAvatars(PriorityAttackMob, _("Priority mobs"), PRIORITY); + // TRANSLATORS: mobs group name in social window + addAvatars(AttackMob, _("Attack mobs"), ATTACK); + // TRANSLATORS: mobs group name in social window + addAvatars(IgnoreAttackMob, _("Ignore mobs"), IGNORE_); + } + +private: + BeingsListModal *mBeings; +}; + +class SocialPickupTab final : public SocialTab +{ +public: + SocialPickupTab(const Widget2 *const widget, + const bool showBackground) : + SocialTab(widget), + mBeings(new BeingsListModal) + { + mList = new AvatarListBox(this, mBeings); + mScroll = new ScrollArea(mList, showBackground, + "social_background.xml"); + + mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); + mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); + + // TRANSLATORS: Pickup filter tab name in social window. Should be small + setCaption(_("Pik")); + } + + A_DELETE_COPY(SocialPickupTab) + + ~SocialPickupTab() + { + delete mList; + mList = nullptr; + delete mScroll; + mScroll = nullptr; + delete mBeings; + mBeings = nullptr; + } + + void updateList() override + { + updateAtkListStart(); + // TRANSLATORS: items group name in social window + addAvatars(PickupItem, _("Pickup items"), PICKUP); + // TRANSLATORS: items group name in social window + addAvatars(IgnorePickupItem, _("Ignore items"), NOPICKUP); + } + +private: + BeingsListModal *mBeings; +}; + + +class SocialFriendsTab final : public SocialTab +{ +public: + SocialFriendsTab(const Widget2 *const widget, + std::string name, const bool showBackground) : + SocialTab(widget), + mBeings(new BeingsListModal) + { + mList = new AvatarListBox(this, mBeings); + mScroll = new ScrollArea(mList, showBackground, + "social_background.xml"); + + mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_AUTO); + mScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); + + updateList(); + setCaption(name); + } + + A_DELETE_COPY(SocialFriendsTab) + + ~SocialFriendsTab() + { + delete mList; + mList = nullptr; + delete mScroll; + mScroll = nullptr; + delete mBeings; + mBeings = nullptr; + } + + void updateList() override + { + getPlayersAvatars(); + } + + void getPlayersAvatars() + { + if (!actorSpriteManager) + return; + + std::vector *const avatars = mBeings->getMembers(); + if (!avatars) + return; + + std::vector::iterator ia = avatars->begin(); + while (ia != avatars->end()) + { + delete *ia; + ++ ia; + } + avatars->clear(); + + const StringVect *const players + = player_relations.getPlayersByRelation(PlayerRelation::FRIEND); + + const std::set &players2 = whoIsOnline->getOnlineNicks(); + + if (!players) + return; + + int online = 0; + int total = 0; + + FOR_EACHP (StringVectCIter, it, players) + { + Avatar *const ava = new Avatar(*it); + if (actorSpriteManager->findBeingByName(*it, Being::PLAYER) + || players2.find(*it) != players2.end()) + { + ava->setOnline(true); + online ++; + } + total ++; + avatars->push_back(ava); + } + std::sort(avatars->begin(), avatars->end(), friendSorter); + delete players; + + // TRANSLATORS: social window label + mCounterString = strprintf(_("Friends: %u/%u"), online, total); + updateCounter(); + } + +private: + BeingsListModal *mBeings; +}; + + +class CreatePopup final : public Popup, public LinkHandler +{ +public: + CreatePopup() : + Popup("SocialCreatePopup"), + LinkHandler(), + mBrowserBox(new BrowserBox(this)) + { + mBrowserBox->setPosition(4, 4); + mBrowserBox->setHighlightMode(BrowserBox::BACKGROUND); + mBrowserBox->setOpaque(false); + mBrowserBox->setLinkHandler(this); + + // TRANSLATORS: party popup item + mBrowserBox->addRow(strprintf("@@party|%s@@", _("Create Party"))); + mBrowserBox->addRow("##3---"); + // TRANSLATORS: party popup item + mBrowserBox->addRow(strprintf("@@cancel|%s@@", _("Cancel"))); + + add(mBrowserBox); + + setContentSize(mBrowserBox->getWidth() + 8, + mBrowserBox->getHeight() + 8); + } + + A_DELETE_COPY(CreatePopup) + + void handleLink(const std::string &link, + gcn::MouseEvent *event A_UNUSED) override + { + if (link == "guild" && socialWindow) + { + socialWindow->showGuildCreate(); + } + else if (link == "party" && socialWindow) + { + socialWindow->showPartyCreate(); + } + + setVisible(false); + } + + void show(gcn::Widget *parent) + { + if (!parent) + return; + + int x, y; + parent->getAbsolutePosition(x, y); + y += parent->getHeight(); + setPosition(x, y); + setVisible(true); + requestMoveToTop(); + } + +private: + BrowserBox* mBrowserBox; +}; + +SocialWindow::SocialWindow() : + // TRANSLATORS: social window name + Window(_("Social"), false, nullptr, "social.xml"), + gcn::ActionListener(), + mGuildInvited(0), + mGuildAcceptDialog(nullptr), + mGuildCreateDialog(nullptr), + mPartyInviter(), + mPartyAcceptDialog(nullptr), + mPartyCreateDialog(nullptr), + mGuilds(), + mParties(), + mAttackFilter(nullptr), + mPickupFilter(nullptr), + // TRANSLATORS: here P is title for visible players tab in social window + mPlayers(new SocialPlayersTab(this, _("P"), + getOptionBool("showtabbackground"))), + mNavigation(new SocialNavigationTab(this, + getOptionBool("showtabbackground"))), + // TRANSLATORS: here F is title for friends tab in social window + mFriends(new SocialFriendsTab(this, _("F"), + getOptionBool("showtabbackground"))), + mCreatePopup(new CreatePopup), + // TRANSLATORS: social window button + mCreateButton(new Button(this, _("Create"), "create", this)), + // TRANSLATORS: social window button + mInviteButton(new Button(this, _("Invite"), "invite", this)), + // TRANSLATORS: social window button + mLeaveButton(new Button(this, _("Leave"), "leave", this)), + mCountLabel(new Label(this, "1000 / 1000")), + mTabs(new TabbedArea(this)), + mMap(nullptr), + mLastUpdateTime(0), + mNeedUpdate(false), + mProcessedPortals(false) +{ + setWindowName("Social"); + setVisible(false); + setSaveVisible(true); + setResizable(true); + setSaveVisible(true); + setCloseButton(true); + setStickyButtonLock(true); + + setMinWidth(120); + setMinHeight(55); + setDefaultSize(590, 200, 180, 300); + if (setupWindow) + setupWindow->registerWindowForReset(this); + + place(0, 0, mCreateButton); + place(1, 0, mInviteButton); + place(2, 0, mLeaveButton); + place(0, 1, mCountLabel); + place(0, 2, mTabs, 4, 4); + + widgetResized(gcn::Event(nullptr)); + + loadWindowState(); + + mTabs->addTab(mPlayers, mPlayers->mScroll); + mTabs->addTab(mFriends, mFriends->mScroll); + mTabs->addTab(mNavigation, mNavigation->mScroll); + + if (config.getBoolValue("enableAttackFilter")) + { + mAttackFilter = new SocialAttackTab(this, + getOptionBool("showtabbackground")); + mTabs->addTab(mAttackFilter, mAttackFilter->mScroll); + } + else + { + mAttackFilter = nullptr; + } + + if (config.getBoolValue("enablePickupFilter")) + { + mPickupFilter = new SocialPickupTab(this, + getOptionBool("showtabbackground")); + mTabs->addTab(mPickupFilter, mPickupFilter->mScroll); + } + else + { + mPickupFilter = nullptr; + } + + if (player_node && player_node->getParty()) + addTab(player_node->getParty()); + + if (player_node && player_node->getGuild()) + addTab(player_node->getGuild()); + + enableVisibleSound(true); + updateButtons(); +} + +SocialWindow::~SocialWindow() +{ + if (mGuildAcceptDialog) + { + mGuildAcceptDialog->close(); + mGuildAcceptDialog->scheduleDelete(); + mGuildAcceptDialog = nullptr; + + mGuildInvited = 0; + } + + if (mPartyAcceptDialog) + { + mPartyAcceptDialog->close(); + mPartyAcceptDialog->scheduleDelete(); + mPartyAcceptDialog = nullptr; + + mPartyInviter.clear(); + } + delete mCreatePopup; + mCreatePopup = nullptr; + delete mPlayers; + mPlayers = nullptr; + delete mNavigation; + mNavigation = nullptr; + delete mAttackFilter; + mAttackFilter = nullptr; + delete mPickupFilter; + mPickupFilter = nullptr; + delete mFriends; + mFriends = nullptr; +} + +bool SocialWindow::addTab(Guild *const guild) +{ + if (mGuilds.find(guild) != mGuilds.end()) + return false; + + SocialTab *tab = nullptr; + if (guild->getServerGuild()) + { + tab = new SocialGuildTab(this, guild, + getOptionBool("showtabbackground")); + } + else + { + tab = new SocialGuildTab2(this, guild, + getOptionBool("showtabbackground")); + } + + mGuilds[guild] = tab; + mTabs->addTab(tab, tab->mScroll); + + updateButtons(); + + return true; +} + +bool SocialWindow::removeTab(Guild *const guild) +{ + const GuildMap::iterator it = mGuilds.find(guild); + if (it == mGuilds.end()) + return false; + + mTabs->removeTab(it->second); + delete it->second; + mGuilds.erase(it); + + updateButtons(); + + return true; +} + +bool SocialWindow::addTab(Party *const party) +{ + if (mParties.find(party) != mParties.end()) + return false; + + SocialPartyTab *const tab = new SocialPartyTab(this, party, + getOptionBool("showtabbackground")); + mParties[party] = tab; + + mTabs->addTab(tab, tab->mScroll); + + updateButtons(); + + return true; +} + +bool SocialWindow::removeTab(Party *const party) +{ + const PartyMap::iterator it = mParties.find(party); + if (it == mParties.end()) + return false; + + mTabs->removeTab(it->second); + delete it->second; + mParties.erase(it); + + updateButtons(); + + return true; +} + +void SocialWindow::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + + if (event.getSource() == mPartyAcceptDialog) + { + if (eventId == "yes") + { + if (localChatTab) + { + localChatTab->chatLog( + // TRANSLATORS: chat message + strprintf(_("Accepted party invite from %s."), + mPartyInviter.c_str())); + } + Net::getPartyHandler()->inviteResponse(mPartyInviter, true); + } + else if (eventId == "no") + { + if (localChatTab) + { + localChatTab->chatLog( + // TRANSLATORS: chat message + strprintf(_("Rejected party invite from %s."), + mPartyInviter.c_str())); + } + Net::getPartyHandler()->inviteResponse(mPartyInviter, false); + } + + mPartyInviter.clear(); + mPartyAcceptDialog = nullptr; + } + else if (event.getSource() == mGuildAcceptDialog) + { + if (eventId == "yes") + { + if (localChatTab) + { + localChatTab->chatLog( + // TRANSLATORS: chat message + strprintf(_("Accepted guild invite from %s."), + mPartyInviter.c_str())); + } + if (!guildManager || !GuildManager::getEnableGuildBot()) + Net::getGuildHandler()->inviteResponse(mGuildInvited, true); + else + guildManager->inviteResponse(true); + } + else if (eventId == "no") + { + if (localChatTab) + { + localChatTab->chatLog( + // TRANSLATORS: chat message + strprintf(_("Rejected guild invite from %s."), + mPartyInviter.c_str())); + } + if (!guildManager || !GuildManager::getEnableGuildBot()) + Net::getGuildHandler()->inviteResponse(mGuildInvited, false); + else + guildManager->inviteResponse(false); + } + + mGuildInvited = 0; + mGuildAcceptDialog = nullptr; + } + else if (eventId == "create") + { + showPartyCreate(); + } + else if (eventId == "invite" && mTabs->getSelectedTabIndex() > -1) + { + if (mTabs->getSelectedTab()) + static_cast(mTabs->getSelectedTab())->invite(); + } + else if (eventId == "leave" && mTabs->getSelectedTabIndex() > -1) + { + if (mTabs->getSelectedTab()) + static_cast(mTabs->getSelectedTab())->leave(); + } + else if (eventId == "create guild") + { + if (tmwServerVersion > 0) + return; + + std::string name = mGuildCreateDialog->getText(); + + if (name.size() > 16) + return; + + Net::getGuildHandler()->create(name); + if (localChatTab) + { + // TRANSLATORS: chat message + localChatTab->chatLog(strprintf(_("Creating guild called %s."), + name.c_str()), BY_SERVER); + } + + mGuildCreateDialog = nullptr; + } + else if (eventId == "~create guild") + { + mGuildCreateDialog = nullptr; + } + else if (eventId == "create party") + { + std::string name = mPartyCreateDialog->getText(); + + if (name.size() > 16) + return; + + Net::getPartyHandler()->create(name); + if (localChatTab) + { + // TRANSLATORS: chat message + localChatTab->chatLog(strprintf(_("Creating party called %s."), + name.c_str()), BY_SERVER); + } + + mPartyCreateDialog = nullptr; + } + else if (eventId == "~create party") + { + mPartyCreateDialog = nullptr; + } +} + +void SocialWindow::showGuildCreate() +{ + // TRANSLATORS: guild creation message + mGuildCreateDialog = new TextDialog(_("Guild Name"), + // TRANSLATORS: guild creation message + _("Choose your guild's name."), this); + mGuildCreateDialog->setActionEventId("create guild"); + mGuildCreateDialog->addActionListener(this); +} + +void SocialWindow::showGuildInvite(const std::string &guildName, + const int guildId, + const std::string &inviterName) +{ + // check there isnt already an invite showing + if (mGuildInvited != 0) + { + if (localChatTab) + { + // TRANSLATORS: chat message + localChatTab->chatLog(_("Received guild request, but one already " + "exists."), BY_SERVER); + } + return; + } + + const std::string msg = strprintf( + // TRANSLATORS: chat message + _("%s has invited you to join the guild %s."), + inviterName.c_str(), guildName.c_str()); + + if (localChatTab) + localChatTab->chatLog(msg, BY_SERVER); + + // TRANSLATORS: guild invite message + mGuildAcceptDialog = new ConfirmDialog(_("Accept Guild Invite"), + msg, SOUND_REQUEST, false, false, this); + mGuildAcceptDialog->addActionListener(this); + mGuildInvited = guildId; +} + +void SocialWindow::showPartyInvite(const std::string &partyName, + const std::string &inviter) +{ + // check there isnt already an invite showing + if (!mPartyInviter.empty()) + { + if (localChatTab) + { + // TRANSLATORS: chat message + localChatTab->chatLog(_("Received party request, but one already " + "exists."), BY_SERVER); + } + return; + } + + std::string msg; + if (inviter.empty()) + { + if (partyName.empty()) + { + // TRANSLATORS: party invite message + msg = _("You have been invited you to join a party."); + } + else + { + // TRANSLATORS: party invite message + msg = strprintf(_("You have been invited to join the %s party."), + partyName.c_str()); + } + } + else + { + if (partyName.empty()) + { + // TRANSLATORS: party invite message + msg = strprintf(_("%s has invited you to join their party."), + inviter.c_str()); + } + else + { + // TRANSLATORS: party invite message + msg = strprintf(_("%s has invited you to join the %s party."), + inviter.c_str(), partyName.c_str()); + } + } + + if (localChatTab) + localChatTab->chatLog(msg, BY_SERVER); + + // show invite + // TRANSLATORS: party invite message + mPartyAcceptDialog = new ConfirmDialog(_("Accept Party Invite"), + msg, SOUND_REQUEST, false, false, this); + mPartyAcceptDialog->addActionListener(this); + mPartyInviter = inviter; +} + +void SocialWindow::showPartyCreate() +{ + if (!player_node) + return; + + if (player_node->getParty()) + { + // TRANSLATORS: party creation message + new OkDialog(_("Create Party"), + _("Cannot create party. You are already in a party"), + DIALOG_ERROR, true, true, this); + return; + } + + // TRANSLATORS: party creation message + mPartyCreateDialog = new TextDialog(_("Party Name"), + // TRANSLATORS: party creation message + _("Choose your party's name."), this); + mPartyCreateDialog->setActionEventId("create party"); + mPartyCreateDialog->addActionListener(this); +} + +void SocialWindow::updateActiveList() +{ + mNeedUpdate = true; +} + +void SocialWindow::slowLogic() +{ + BLOCK_START("SocialWindow::slowLogic") + const unsigned int nowTime = cur_time; + if (mNeedUpdate && nowTime - mLastUpdateTime > 1) + { + mPlayers->updateList(); + mFriends->updateList(); + mNeedUpdate = false; + mLastUpdateTime = nowTime; + } + else if (nowTime - mLastUpdateTime > 5) + { + mPlayers->updateList(); + mNeedUpdate = false; + mLastUpdateTime = nowTime; + } + BLOCK_END("SocialWindow::slowLogic") +} + +void SocialWindow::updateAvatar(const std::string &name) +{ + mPlayers->updateAvatar(name); +} + +void SocialWindow::resetDamage(const std::string &name) +{ + mPlayers->resetDamage(name); +} + +void SocialWindow::updateButtons() +{ + if (!mTabs) + return; + + const bool hasTabs = mTabs->getNumberOfTabs() > 0; + mInviteButton->setEnabled(hasTabs); + mLeaveButton->setEnabled(hasTabs); +} + +void SocialWindow::updatePortals() +{ + if (mNavigation) + mNavigation->updateList(); +} + +void SocialWindow::updatePortalNames() +{ + if (mNavigation) + static_cast(mNavigation)->updateNames(); +} + +void SocialWindow::selectPortal(const unsigned num) +{ + if (mNavigation) + mNavigation->selectIndex(num); +} + +int SocialWindow::getPortalIndex(const int x, const int y) +{ + if (mNavigation) + { + return static_cast( + mNavigation)->getPortalIndex(x, y); + } + else + { + return -1; + } +} + +void SocialWindow::addPortal(const int x, const int y) +{ + if (mNavigation) + static_cast(mNavigation)->addPortal(x, y); +} + +void SocialWindow::removePortal(const int x, const int y) +{ + if (mNavigation) + static_cast(mNavigation)->removePortal(x, y); +} + +void SocialWindow::nextTab() +{ + if (!mTabs) + return; + + int tab = mTabs->getSelectedTabIndex(); + + tab++; + if (tab == mTabs->getNumberOfTabs()) + tab = 0; + + mTabs->setSelectedTabByPos(tab); +} + +void SocialWindow::prevTab() +{ + if (!mTabs) + return; + + int tab = mTabs->getSelectedTabIndex(); + + if (tab == 0) + tab = mTabs->getNumberOfTabs(); + tab--; + + mTabs->setSelectedTabByPos(tab); +} + +void SocialWindow::updateAttackFilter() +{ + if (mAttackFilter) + mAttackFilter->updateList(); +} + +void SocialWindow::updatePickupFilter() +{ + if (mPickupFilter) + mPickupFilter->updateList(); +} + +void SocialWindow::updateParty() +{ + if (!player_node) + return; + + Party *const party = player_node->getParty(); + if (party) + { + PartyMap::iterator it = mParties.find(party); + if (it != mParties.end()) + { + SocialTab *const tab = (*it).second; + tab->buildCounter(); + } + } +} + +void SocialWindow::widgetResized(const gcn::Event &event) +{ + Window::widgetResized(event); + if (mTabs) + mTabs->adjustSize(); +} + +void SocialWindow::setCounter(const SocialTab *const tab, + const std::string &str) +{ + if (mTabs->getSelectedTab() == tab) + { + mCountLabel->setCaption(str); + mCountLabel->adjustSize(); + } +} + +void SocialWindow::updateGuildCounter(const int online, const int total) +{ + if (!player_node) + return; + + Guild *const guild = player_node->getGuild(); + if (guild) + { + GuildMap::iterator it = mGuilds.find(guild); + if (it != mGuilds.end()) + { + SocialTab *const tab = (*it).second; + tab->buildCounter(online, total); + } + } +} + +#ifdef USE_PROFILER +void SocialWindow::logicChildren() +{ + BLOCK_START("SocialWindow::logicChildren") + BasicContainer::logicChildren(); + BLOCK_END("SocialWindow::logicChildren") +} +#endif diff --git a/src/gui/windows/socialwindow.h b/src/gui/windows/socialwindow.h new file mode 100644 index 000000000..31d1b676a --- /dev/null +++ b/src/gui/windows/socialwindow.h @@ -0,0 +1,170 @@ +/* + * The ManaPlus Client + * Copyright (C) 2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_SOCIALWINDOW_H +#define GUI_SOCIALWINDOW_H + +#include "gui/widgets/window.h" + +#include + +#include +#include + +class Button; +class ConfirmDialog; +class CreatePopup; +class Guild; +class Label; +class Map; +class Party; +class SocialTab; +class TabbedArea; +class TextDialog; + +/** + * Party window. + * + * \ingroup Interface + */ +class SocialWindow final : public Window, private gcn::ActionListener +{ +public: + SocialWindow(); + + A_DELETE_COPY(SocialWindow) + + ~SocialWindow(); + + bool addTab(Guild *const guild); + + bool removeTab(Guild *const guild); + + bool addTab(Party *const party); + + bool removeTab(Party *const party); + + void action(const gcn::ActionEvent &event) override; + + void showGuildInvite(const std::string &guildName, const int guildId, + const std::string &inviterName); + + void showGuildCreate(); + + void showPartyInvite(const std::string &partyName, + const std::string &inviter = ""); + + void showPartyCreate(); + + void updateActiveList(); + + void updateAvatar(const std::string &name); + + void resetDamage(const std::string &name); + + void slowLogic(); + + void updatePortals(); + + void updatePortalNames(); + + void updateParty(); + + int getPortalIndex(const int x, const int y) A_WARN_UNUSED; + + void addPortal(const int x, const int y); + + void removePortal(const int x, const int y); + + void nextTab(); + + void prevTab(); + + const Map* getMap() const A_WARN_UNUSED + { return mMap; } + + void setMap(Map *const map) + { mMap = map; mProcessedPortals = false; } + + bool getProcessedPortals() const A_WARN_UNUSED + { return mProcessedPortals; } + + void setProcessedPortals(const bool n) + { mProcessedPortals = n; } + + void selectPortal(const unsigned num); + + void updateAttackFilter(); + + void updatePickupFilter(); + + void widgetResized(const gcn::Event &event) override; + + void setCounter(const SocialTab *const tab, const std::string &str); + + void updateGuildCounter(const int online = 0, const int total = 0); + +#ifdef USE_PROFILER + void logicChildren(); +#endif + +protected: + friend class SocialTab; + + void updateButtons(); + + int mGuildInvited; + ConfirmDialog *mGuildAcceptDialog; + TextDialog *mGuildCreateDialog; + + std::string mPartyInviter; + ConfirmDialog *mPartyAcceptDialog; + TextDialog *mPartyCreateDialog; + + typedef std::map GuildMap; + GuildMap mGuilds; + + typedef std::map PartyMap; + PartyMap mParties; + + SocialTab *mAttackFilter; + SocialTab *mPickupFilter; + SocialTab *mPlayers; + SocialTab *mNavigation; + SocialTab *mFriends; + + CreatePopup *mCreatePopup; + + Button *mCreateButton; + Button *mInviteButton; + Button *mLeaveButton; + Label *mCountLabel; + TabbedArea *mTabs; + Map *mMap; + + int mLastUpdateTime; + bool mNeedUpdate; + bool mProcessedPortals; +}; + +extern SocialWindow *socialWindow; + +#endif // GUI_SOCIALWINDOW_H diff --git a/src/gui/windows/statuswindow.cpp b/src/gui/windows/statuswindow.cpp new file mode 100644 index 000000000..bbc4558b0 --- /dev/null +++ b/src/gui/windows/statuswindow.cpp @@ -0,0 +1,888 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/statuswindow.h" + +#include "configuration.h" +#include "equipment.h" +#include "inventory.h" +#include "item.h" +#include "units.h" + +#include "gui/windows/chatwindow.h" + +#include "being/localplayer.h" +#include "being/playerinfo.h" + +#include "gui/viewport.h" + +#include "gui/windows/equipmentwindow.h" +#include "gui/windows/setup.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/label.h" +#include "gui/widgets/layouthelper.h" +#include "gui/widgets/progressbar.h" +#include "gui/widgets/scrollarea.h" +#include "gui/widgets/vertcontainer.h" + +#include "net/net.h" +#include "net/playerhandler.h" +#include "net/gamehandler.h" + +#include "utils/gettext.h" + +#include + +#include "debug.h" + +class AttrDisplay : public Container +{ + public: + enum Type + { + DERIVED = 0, + CHANGEABLE, + UNKNOWN + }; + + A_DELETE_COPY(AttrDisplay) + + virtual ~AttrDisplay(); + + virtual std::string update(); + + virtual Type getType() const + { return UNKNOWN; } + + std::string getValue() const + { + if (!mValue) + return "-"; + else + return mValue->getCaption(); + } + + const std::string &getShortName() const + { return mShortName; } + + protected: + AttrDisplay(const Widget2 *const widget, + const int id, const std::string &name, + const std::string &shortName); + + const int mId; + const std::string mName; + const std::string mShortName; + + LayoutHelper *mLayout; + Label *mLabel; + Label *mValue; +}; + +class DerDisplay final : public AttrDisplay +{ + public: + DerDisplay(const Widget2 *const widget, + const int id, const std::string &name, + const std::string &shortName); + + A_DELETE_COPY(DerDisplay) + + Type getType() const override + { return DERIVED; } +}; + +class ChangeDisplay final : public AttrDisplay, gcn::ActionListener +{ + public: + ChangeDisplay(const Widget2 *const widget, + const int id, const std::string &name, + const std::string &shortName); + + A_DELETE_COPY(ChangeDisplay) + + std::string update() override; + + Type getType() const override + { return CHANGEABLE; } + + void setPointsNeeded(int needed); + + void action(const gcn::ActionEvent &event) override; + + private: + int mNeeded; + + Label *mPoints; + Button *mDec; + Button *mInc; +}; + +StatusWindow::StatusWindow() : + Window(player_node ? player_node->getName() : + "?", false, nullptr, "status.xml"), + gcn::ActionListener(), + // TRANSLATORS: status window label + mLvlLabel(new Label(this, strprintf(_("Level: %d"), 0))), + // TRANSLATORS: status window label + mMoneyLabel(new Label(this, strprintf(_("Money: %s"), ""))), + // TRANSLATORS: status window label + mHpLabel(new Label(this, _("HP:"))), + mMpLabel(nullptr), + // TRANSLATORS: status window label + mXpLabel(new Label(this, _("Exp:"))), + mHpBar(nullptr), + mMpBar(nullptr), + mXpBar(nullptr), + mJobLvlLabel(nullptr), + mJobLabel(nullptr), + mJobBar(nullptr), + mAttrCont(new VertContainer(this, 32)), + mAttrScroll(new ScrollArea(mAttrCont, false)), + mDAttrCont(new VertContainer(this, 32)), + mDAttrScroll(new ScrollArea(mDAttrCont, false)), + mCharacterPointsLabel(new Label(this, "C")), + mCorrectionPointsLabel(nullptr), + // TRANSLATORS: status window button + mCopyButton(new Button(this, _("Copy to chat"), "copy", this)), + mAttrs() +{ + listen(CHANNEL_ATTRIBUTES); + + setWindowName("Status"); + if (setupWindow) + setupWindow->registerWindowForReset(this); + setResizable(true); + setCloseButton(true); + setSaveVisible(true); + setStickyButtonLock(true); + setDefaultSize((windowContainer->getWidth() - 480) / 2, + (windowContainer->getHeight() - 500) / 2, 480, 500); + + if (player_node && !player_node->getRaceName().empty()) + { + setCaption(strprintf("%s (%s)", player_node->getName().c_str(), + player_node->getRaceName().c_str())); + } + + int max = PlayerInfo::getAttribute(PlayerInfo::MAX_HP); + if (!max) + max = 1; + + mHpBar = new ProgressBar(this, static_cast(PlayerInfo::getAttribute( + PlayerInfo::HP)) / static_cast(max), 80, 0, Theme::PROG_HP); + + max = PlayerInfo::getAttribute(PlayerInfo::EXP_NEEDED); + mXpBar = new ProgressBar(this, max ? + static_cast(PlayerInfo::getAttribute(PlayerInfo::EXP)) + / static_cast(max): + static_cast(0), 80, 0, Theme::PROG_EXP); + + const bool magicBar = Net::getGameHandler()->canUseMagicBar(); + const int job = Net::getPlayerHandler()->getJobLocation() + && serverConfig.getValueBool("showJob", true); + + if (magicBar) + { + max = PlayerInfo::getAttribute(PlayerInfo::MAX_MP); + // TRANSLATORS: status window label + mMpLabel = new Label(this, _("MP:")); + mMpBar = new ProgressBar(this, max ? static_cast( + PlayerInfo::getAttribute(PlayerInfo::MAX_MP)) + / static_cast(max) : static_cast(0), + 80, 0, Net::getPlayerHandler()->canUseMagic() ? + Theme::PROG_MP : Theme::PROG_NO_MP); + } + else + { + mMpLabel = nullptr; + mMpBar = nullptr; + } + + place(0, 0, mLvlLabel, 3); + place(0, 1, mHpLabel).setPadding(3); + place(1, 1, mHpBar, 4); + place(5, 1, mXpLabel).setPadding(3); + place(6, 1, mXpBar, 5); + if (magicBar) + { + place(0, 2, mMpLabel).setPadding(3); + // 5, 2 and 6, 2 Job Progress Bar + if (job) + place(1, 2, mMpBar, 4); + else + place(1, 2, mMpBar, 10); + } + + if (job) + { + // TRANSLATORS: status window label + mJobLvlLabel = new Label(this, strprintf(_("Job: %d"), 0)); + // TRANSLATORS: status window label + mJobLabel = new Label(this, _("Job:")); + mJobBar = new ProgressBar(this, 0.0F, 80, 0, Theme::PROG_JOB); + + place(3, 0, mJobLvlLabel, 3); + place(5, 2, mJobLabel).setPadding(3); + place(6, 2, mJobBar, 5); + place(6, 0, mMoneyLabel, 3); + } + else + { + mJobLvlLabel = nullptr; + mJobLabel = nullptr; + mJobBar = nullptr; + place(3, 0, mMoneyLabel, 3); + } + + // ---------------------- + // Stats Part + // ---------------------- + + mAttrScroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); + mAttrScroll->setVerticalScrollPolicy(ScrollArea::SHOW_AUTO); + place(0, 3, mAttrScroll, 5, 3); + + mDAttrScroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); + mDAttrScroll->setVerticalScrollPolicy(ScrollArea::SHOW_AUTO); + place(6, 3, mDAttrScroll, 5, 3); + + getLayout().setRowHeight(3, Layout::AUTO_SET); + + place(0, 6, mCharacterPointsLabel, 5); + place(0, 5, mCopyButton); + + if (Net::getPlayerHandler()->canCorrectAttributes()) + { + mCorrectionPointsLabel = new Label(this, "C"); + place(0, 7, mCorrectionPointsLabel, 5); + } + + loadWindowState(); + enableVisibleSound(true); + + // Update bars + updateHPBar(mHpBar, true); + if (magicBar) + updateMPBar(mMpBar, true); + updateXPBar(mXpBar, false); + + // TRANSLATORS: status window label + mMoneyLabel->setCaption(strprintf(_("Money: %s"), Units::formatCurrency( + PlayerInfo::getAttribute(PlayerInfo::MONEY)).c_str())); + mMoneyLabel->adjustSize(); + // TRANSLATORS: status window label + mCharacterPointsLabel->setCaption(strprintf(_("Character points: %d"), + PlayerInfo::getAttribute(PlayerInfo::CHAR_POINTS))); + mCharacterPointsLabel->adjustSize(); + + if (player_node && player_node->isGM()) + { + // TRANSLATORS: status window label + mLvlLabel->setCaption(strprintf(_("Level: %d (GM %d)"), + PlayerInfo::getAttribute(PlayerInfo::LEVEL), + player_node->getGMLevel())); + } + else + { + // TRANSLATORS: status window label + mLvlLabel->setCaption(strprintf(_("Level: %d"), + PlayerInfo::getAttribute(PlayerInfo::LEVEL))); + } + mLvlLabel->adjustSize(); +} + +void StatusWindow::processEvent(const Channels channel A_UNUSED, + const DepricatedEvent &event) +{ + static bool blocked = false; + if (blocked) + return; + + const DepricatedEvents &eventName = event.getName(); + if (eventName == EVENT_UPDATEATTRIBUTE) + { + switch (event.getInt("id")) + { + case PlayerInfo::HP: + case PlayerInfo::MAX_HP: + updateHPBar(mHpBar, true); + break; + + case PlayerInfo::MP: + case PlayerInfo::MAX_MP: + updateMPBar(mMpBar, true); + break; + + case PlayerInfo::EXP: + case PlayerInfo::EXP_NEEDED: + updateXPBar(mXpBar, false); + break; + + case PlayerInfo::MONEY: + // TRANSLATORS: status window label + mMoneyLabel->setCaption(strprintf(_("Money: %s"), + Units::formatCurrency(event.getInt("newValue")).c_str())); + mMoneyLabel->adjustSize(); + break; + + case PlayerInfo::CHAR_POINTS: + mCharacterPointsLabel->setCaption(strprintf( + // TRANSLATORS: status window label + _("Character points: %d"), event.getInt("newValue"))); + + mCharacterPointsLabel->adjustSize(); + // Update all attributes + for (Attrs::const_iterator it = mAttrs.begin(); + it != mAttrs.end(); ++it) + { + if (it->second) + it->second->update(); + } + break; + + case PlayerInfo::CORR_POINTS: + mCorrectionPointsLabel->setCaption(strprintf( + // TRANSLATORS: status window label + _("Correction points: %d"), event.getInt("newValue"))); + mCorrectionPointsLabel->adjustSize(); + // Update all attributes + for (Attrs::const_iterator it = mAttrs.begin(); + it != mAttrs.end(); ++it) + { + if (it->second) + it->second->update(); + } + break; + + case PlayerInfo::LEVEL: + // TRANSLATORS: status window label + mLvlLabel->setCaption(strprintf(_("Level: %d"), + event.getInt("newValue"))); + mLvlLabel->adjustSize(); + break; + + default: + break; + } + } + else if (eventName == EVENT_UPDATESTAT) + { + const int id = event.getInt("id"); + if (id == Net::getPlayerHandler()->getJobLocation()) + { + if (mJobLvlLabel) + { + int lvl = PlayerInfo::getStatBase(id); + const int oldExp = event.getInt("oldValue1"); + const std::pair exp + = PlayerInfo::getStatExperience(id); + + if (!lvl) + { + // possible server broken and don't send job level, + // then we fixing it :) + if (exp.second < 20000) + { + lvl = 0; + } + else + { + lvl = (exp.second - 20000) / 150; + blocked = true; + PlayerInfo::setStatBase(id, lvl); + blocked = false; + } + } + + if (exp.first < oldExp && exp.second >= 20000) + { // possible job level up. but server broken and don't send + // new job exp limit, we fixing it + lvl ++; + blocked = true; + PlayerInfo::setStatExperience( + id, exp.first, 20000 + lvl * 150); + PlayerInfo::setStatBase(id, lvl); + blocked = false; + } + + // TRANSLATORS: status window label + mJobLvlLabel->setCaption(strprintf(_("Job: %d"), lvl)); + mJobLvlLabel->adjustSize(); + + updateProgressBar(mJobBar, id, false); + } + } + else + { + updateMPBar(mMpBar, true); + const Attrs::const_iterator it = mAttrs.find(id); + if (it != mAttrs.end() && it->second) + it->second->update(); + } + } +} + +void StatusWindow::setPointsNeeded(const int id, const int needed) +{ + const Attrs::const_iterator it = mAttrs.find(id); + + if (it != mAttrs.end()) + { + AttrDisplay *const disp = it->second; + if (disp && disp->getType() == AttrDisplay::CHANGEABLE) + static_cast(disp)->setPointsNeeded(needed); + } +} + +void StatusWindow::addAttribute(const int id, const std::string &name, + const std::string &shortName, + const bool modifiable, + const std::string &description A_UNUSED) +{ + AttrDisplay *disp; + + if (modifiable) + { + disp = new ChangeDisplay(this, id, name, shortName); + mAttrCont->add1(disp); + } + else + { + disp = new DerDisplay(this, id, name, shortName); + mDAttrCont->add1(disp); + } + mAttrs[id] = disp; +} + +void StatusWindow::clearAttributes() +{ + mAttrCont->clear(); + mDAttrCont->clear(); + FOR_EACH (Attrs::iterator, it, mAttrs) + delete (*it).second; + mAttrs.clear(); +} + +void StatusWindow::updateHPBar(ProgressBar *const bar, const bool showMax) +{ + if (!bar) + return; + + const int hp = PlayerInfo::getAttribute(PlayerInfo::HP); + const int maxHp = PlayerInfo::getAttribute(PlayerInfo::MAX_HP); + if (showMax) + bar->setText(toString(hp).append("/").append(toString(maxHp))); + else + bar->setText(toString(hp)); + + float prog = 1.0; + if (maxHp > 0) + prog = static_cast(hp) / static_cast(maxHp); + bar->setProgress(prog); +} + +void StatusWindow::updateMPBar(ProgressBar *const bar, const bool showMax) +{ + if (!bar) + return; + + const int mp = PlayerInfo::getAttribute(PlayerInfo::MP); + const int maxMp = PlayerInfo::getAttribute(PlayerInfo::MAX_MP); + if (showMax) + bar->setText(toString(mp).append("/").append(toString(maxMp))); + else + bar->setText(toString(mp)); + + float prog = 1.0F; + if (maxMp > 0) + prog = static_cast(mp) / static_cast(maxMp); + + if (Net::getPlayerHandler()->canUseMagic()) + bar->setProgressPalette(Theme::PROG_MP); + else + bar->setProgressPalette(Theme::PROG_NO_MP); + + bar->setProgress(prog); +} + +void StatusWindow::updateProgressBar(ProgressBar *const bar, const int value, + const int max, const bool percent) +{ + if (!bar) + return; + + if (max == 0) + { + // TRANSLATORS: status bar label + bar->setText(_("Max")); + bar->setProgress(1); + bar->setText(toString(value)); + } + else + { + const float progress = static_cast(value) + / static_cast(max); + if (percent) + { + bar->setText(strprintf("%2.5f%%", + static_cast(100 * progress))); + } + else + { + bar->setText(toString(value).append("/").append(toString(max))); + } + bar->setProgress(progress); + } +} + +void StatusWindow::updateXPBar(ProgressBar *const bar, const bool percent) +{ + if (!bar) + return; + + updateProgressBar(bar, PlayerInfo::getAttribute(PlayerInfo::EXP), + PlayerInfo::getAttribute(PlayerInfo::EXP_NEEDED), percent); +} + +void StatusWindow::updateJobBar(ProgressBar *const bar, const bool percent) +{ + if (!bar) + return; + + const std::pair exp = PlayerInfo::getStatExperience( + Net::getPlayerHandler()->getJobLocation()); + updateProgressBar(bar, exp.first, exp.second, percent); +} + +void StatusWindow::updateProgressBar(ProgressBar *const bar, const int id, + const bool percent) const +{ + const std::pair exp = PlayerInfo::getStatExperience(id); + updateProgressBar(bar, exp.first, exp.second, percent); +} + +void StatusWindow::updateWeightBar(ProgressBar *const bar) +{ + if (!bar) + return; + + if (PlayerInfo::getAttribute(PlayerInfo::MAX_WEIGHT) == 0) + { + // TRANSLATORS: status bar label + bar->setText(_("Max")); + bar->setProgress(1.0); + } + else + { + const int totalWeight = PlayerInfo::getAttribute( + PlayerInfo::TOTAL_WEIGHT); + const int maxWeight = PlayerInfo::getAttribute(PlayerInfo::MAX_WEIGHT); + const float progress = static_cast(totalWeight) + / static_cast(maxWeight); + bar->setText(strprintf("%s/%s", Units::formatWeight( + totalWeight).c_str(), Units::formatWeight(maxWeight).c_str())); + bar->setProgress(progress); + } +} + +void StatusWindow::updateMoneyBar(ProgressBar *const bar) +{ + if (!bar) + return; + + const int money = PlayerInfo::getAttribute(PlayerInfo::MONEY); + bar->setText(Units::formatCurrency(money).c_str()); + if (money > 0) + { + const float progress = static_cast(money) + / static_cast(1000000000); + bar->setProgress(progress); + } + else + { + bar->setProgress(1.0); + } +} + +void StatusWindow::updateArrowsBar(ProgressBar *const bar) +{ + if (!bar || !equipmentWindow) + return; + + const Item *const item = equipmentWindow->getEquipment( + Equipment::EQUIP_PROJECTILE_SLOT); + + if (item && item->getQuantity() > 0) + bar->setText(toString(item->getQuantity())); + else + bar->setText("0"); +} + +void StatusWindow::updateInvSlotsBar(ProgressBar *const bar) +{ + if (!bar) + return; + + const Inventory *const inv = PlayerInfo::getInventory(); + if (!inv) + return; + + const int usedSlots = inv->getNumberOfSlotsUsed(); + const int maxSlots = inv->getSize(); + + if (maxSlots) + { + bar->setProgress(static_cast(usedSlots) + / static_cast(maxSlots)); + } + + bar->setText(strprintf("%d", usedSlots)); +} + +std::string StatusWindow::translateLetter(const char *const letters) +{ + char buf[2]; + char *const str = gettext(letters); + if (strlen(str) != 3) + return letters; + + buf[0] = str[1]; + buf[1] = 0; + return std::string(buf); +} + +std::string StatusWindow::translateLetter2(std::string letters) +{ + if (letters.size() < 5) + return ""; + + return std::string(gettext(letters.substr(1, 1).c_str())); +} + +void StatusWindow::updateStatusBar(ProgressBar *const bar, + const bool percent A_UNUSED) +{ + if (!player_node || !viewport) + return; + + bar->setText(translateLetter2(player_node->getInvertDirectionString()) + .append(translateLetter2(player_node->getCrazyMoveTypeString())) + .append(translateLetter2(player_node->getMoveToTargetTypeString())) + .append(translateLetter2(player_node->getFollowModeString())) + .append(" ").append(translateLetter2( + player_node->getAttackWeaponTypeString())) + .append(translateLetter2(player_node->getAttackTypeString())) + .append(translateLetter2(player_node->getMagicAttackString())) + .append(translateLetter2(player_node->getPvpAttackString())) + .append(" ").append(translateLetter2( + player_node->getQuickDropCounterString())) + .append(translateLetter2(player_node->getPickUpTypeString())) + .append(" ").append(translateLetter2( + player_node->getDebugPathString())) + .append(" ").append(translateLetter2( + player_node->getImitationModeString())) + .append(translateLetter2(player_node->getCameraModeString())) + .append(translateLetter2(player_node->getAwayModeString()))); + + bar->setProgress(50); + if (player_node->getDisableGameModifiers()) + bar->setColor(Theme::getThemeColor(Theme::STATUSBAR_ON)); + else + bar->setColor(Theme::getThemeColor(Theme::STATUSBAR_OFF)); +} + +void StatusWindow::action(const gcn::ActionEvent &event) +{ + if (!chatWindow) + return; + + if (event.getId() == "copy") + { + Attrs::const_iterator it = mAttrs.begin(); + const Attrs::const_iterator it_end = mAttrs.end(); + std::string str; + while (it != it_end) + { + const ChangeDisplay *const attr = dynamic_cast( + (*it).second); + if (attr) + { + str.append(strprintf("%s:%s ", attr->getShortName().c_str(), + attr->getValue().c_str())); + } + ++ it; + } + chatWindow->addInputText(str); + } +} + +AttrDisplay::AttrDisplay(const Widget2 *const widget, + const int id, const std::string &name, + const std::string &shortName) : + Container(widget), + mId(id), + mName(name), + mShortName(shortName), + mLayout(new LayoutHelper(this)), + mLabel(new Label(this, name)), + mValue(new Label(this, "1 ")) +{ + setSize(100, 32); + + mLabel->setAlignment(Graphics::CENTER); + mValue->setAlignment(Graphics::CENTER); +} + +AttrDisplay::~AttrDisplay() +{ + delete mLayout; + mLayout = nullptr; +} + +std::string AttrDisplay::update() +{ + const int base = PlayerInfo::getStatBase(mId); + const int bonus = PlayerInfo::getStatMod(mId); + std::string value = toString(base + bonus); + if (bonus) + value.append(strprintf("=%d%+d", base, bonus)); + mValue->setCaption(value); + return mName; +} + +DerDisplay::DerDisplay(const Widget2 *const widget, + const int id, const std::string &name, + const std::string &shortName) : + AttrDisplay(widget, id, name, shortName) +{ + ContainerPlacer place = mLayout->getPlacer(0, 0); + + place(0, 0, mLabel, 3); + place(3, 0, mValue, 2); + + update(); +} + +ChangeDisplay::ChangeDisplay(const Widget2 *const widget, + const int id, const std::string &name, + const std::string &shortName) : + AttrDisplay(widget, id, name, shortName), + gcn::ActionListener(), + mNeeded(1), + // TRANSLATORS: status window label + mPoints(new Label(this, _("Max"))), + mDec(nullptr), + // TRANSLATORS: status window label (plus sign) + mInc(new Button(this, _("+"), "inc", this)) +{ + // Do the layout + ContainerPlacer place = mLayout->getPlacer(0, 0); + + place(0, 0, mLabel, 3); + place(4, 0, mValue, 2); + place(6, 0, mInc); + place(7, 0, mPoints); + + if (Net::getPlayerHandler()->canCorrectAttributes()) + { + // TRANSLATORS: status window label (minus sign) + mDec = new Button(this, _("-"), "dec", this); + mDec->setWidth(mInc->getWidth()); + + place(3, 0, mDec); + } + + update(); +} + +std::string ChangeDisplay::update() +{ + if (mNeeded > 0) + { + mPoints->setCaption(toString(mNeeded)); + } + else + { + // TRANSLATORS: status bar label + mPoints->setCaption(_("Max")); + } + + if (mDec) + mDec->setEnabled(PlayerInfo::getAttribute(PlayerInfo::CORR_POINTS)); + + mInc->setEnabled(PlayerInfo::getAttribute(PlayerInfo::CHAR_POINTS) + >= mNeeded && mNeeded > 0); + + return AttrDisplay::update(); +} + +void ChangeDisplay::setPointsNeeded(const int needed) +{ + mNeeded = needed; + update(); +} + +void ChangeDisplay::action(const gcn::ActionEvent &event) +{ + if (Net::getPlayerHandler()->canCorrectAttributes() && + event.getSource() == mDec) + { + const int newcorrpoints = PlayerInfo::getAttribute( + PlayerInfo::CORR_POINTS); + PlayerInfo::setAttribute(PlayerInfo::CORR_POINTS, newcorrpoints - 1); + + const int newpoints = PlayerInfo::getAttribute( + PlayerInfo::CHAR_POINTS) + 1; + PlayerInfo::setAttribute(PlayerInfo::CHAR_POINTS, newpoints); + + const int newbase = PlayerInfo::getStatBase(mId) - 1; + PlayerInfo::setStatBase(mId, newbase); + + Net::getPlayerHandler()->decreaseAttribute(mId); + } + else if (event.getSource() == mInc) + { + int cnt = 1; + if (config.getBoolValue("quickStats")) + { + cnt = mInc->getClickCount(); + if (cnt > 10) + cnt = 10; + } + + const int newpoints = PlayerInfo::getAttribute( + PlayerInfo::CHAR_POINTS) - cnt; + PlayerInfo::setAttribute(PlayerInfo::CHAR_POINTS, newpoints); + + const int newbase = PlayerInfo::getStatBase(mId) + cnt; + PlayerInfo::setStatBase(mId, newbase); + + for (unsigned f = 0; f < mInc->getClickCount(); f ++) + { + Net::getPlayerHandler()->increaseAttribute(mId); + if (cnt != 1) + SDL_Delay(100); + } + } +} diff --git a/src/gui/windows/statuswindow.h b/src/gui/windows/statuswindow.h new file mode 100644 index 000000000..eebcd12ca --- /dev/null +++ b/src/gui/windows/statuswindow.h @@ -0,0 +1,125 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_STATUSWINDOW_H +#define GUI_STATUSWINDOW_H + +#include "depricatedlistener.h" + +#include "gui/widgets/window.h" + +#include + +#include + +class AttrDisplay; +class Button; +class Label; +class ProgressBar; +class ScrollArea; +class VertContainer; + +/** + * The player status dialog. + * + * \ingroup Interface + */ +class StatusWindow final : public Window, + public gcn::ActionListener, + public DepricatedListener +{ + public: + /** + * Constructor. + */ + StatusWindow(); + + A_DELETE_COPY(StatusWindow) + + void processEvent(const Channels channel, + const DepricatedEvent &event) override; + + void setPointsNeeded(const int id, const int needed); + + void addAttribute(const int id, const std::string &name, + const std::string &shortName = "", + const bool modifiable = false, + const std::string &description = ""); + + static void updateHPBar(ProgressBar *const bar, + const bool showMax = false); + static void updateMPBar(ProgressBar *bar, bool showMax = false); + static void updateJobBar(ProgressBar *const bar, + const bool percent = true); + static void updateXPBar(ProgressBar *const bar, + const bool percent = true); + static void updateWeightBar(ProgressBar *const bar); + static void updateInvSlotsBar(ProgressBar *const bar); + static void updateMoneyBar(ProgressBar *const bar); + static void updateArrowsBar(ProgressBar *const bar); + static void updateStatusBar(ProgressBar *const bar, + const bool percent = true); + static void updateProgressBar(ProgressBar *const bar, const int value, + const int max, const bool percent); + void updateProgressBar(ProgressBar *const bar, const int id, + const bool percent = true) const; + + void action(const gcn::ActionEvent &event) override; + + void clearAttributes(); + + private: + static std::string translateLetter(const char *const letters); + static std::string translateLetter2(std::string letters); + + /** + * Status Part + */ + Label *mLvlLabel; + Label *mMoneyLabel; + Label *mHpLabel; + Label *mMpLabel; + Label *mXpLabel; + ProgressBar *mHpBar; + ProgressBar *mMpBar; + ProgressBar *mXpBar; + + Label *mJobLvlLabel; + Label *mJobLabel; + ProgressBar *mJobBar; + + VertContainer *mAttrCont; + ScrollArea *mAttrScroll; + VertContainer *mDAttrCont; + ScrollArea *mDAttrScroll; + + Label *mCharacterPointsLabel; + Label *mCorrectionPointsLabel; + Button *mCopyButton; + + typedef std::map Attrs; + Attrs mAttrs; +}; + +extern StatusWindow *statusWindow; + +#endif // GUI_STATUSWINDOW_H diff --git a/src/gui/windows/textcommandeditor.cpp b/src/gui/windows/textcommandeditor.cpp new file mode 100644 index 000000000..1b4fb3440 --- /dev/null +++ b/src/gui/windows/textcommandeditor.cpp @@ -0,0 +1,396 @@ +/* + * The ManaPlus Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 Andrei Karas + * Copyright (C) 2011-2013 The ManaPlus developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/textcommandeditor.h" + +#include "main.h" +#include "spellmanager.h" + +#include "input/keyboardconfig.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/dropdown.h" +#include "gui/widgets/inttextfield.h" +#include "gui/widgets/label.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/radiobutton.h" + +#include "utils/gettext.h" + +#include "resources/itemdb.h" +#include "resources/iteminfo.h" + +#include "debug.h" + +class IconsModal final : public gcn::ListModel +{ +public: + IconsModal() : + mStrings() + { + const std::map &items = ItemDB::getItemInfos(); + std::list tempStrings; + + for (std::map::const_iterator + i = items.begin(), i_end = items.end(); + i != i_end; ++i) + { + if (i->first < 0) + continue; + + const ItemInfo &info = (*i->second); + const std::string name = info.getName(); + if (name != "unnamed" && !info.getName().empty() + && info.getName() != "unnamed") + { + tempStrings.push_back(name); + } + } + tempStrings.sort(); + mStrings.push_back(""); + FOR_EACH (std::list::const_iterator, i, tempStrings) + mStrings.push_back(*i); + } + + A_DELETE_COPY(IconsModal) + + ~IconsModal() + { } + + int getNumberOfElements() override + { + return static_cast(mStrings.size()); + } + + std::string getElementAt(int i) override + { + if (i < 0 || i >= getNumberOfElements()) + return "???"; + return mStrings.at(i); + } +private: + StringVect mStrings; +}; + + +const char *TARGET_TYPE_TEXT[3] = +{ + // TRANSLATORS: target type + N_("No Target"), + // TRANSLATORS: target type + N_("Allow Target"), + // TRANSLATORS: target type + N_("Need Target"), +}; + +const char *MAGIC_SCHOOL_TEXT[6] = +{ + // TRANSLATORS: magic school + N_("General Magic"), + // TRANSLATORS: magic school + N_("Life Magic"), + // TRANSLATORS: magic school + N_("War Magic"), + // TRANSLATORS: magic school + N_("Transmute Magic"), + // TRANSLATORS: magic school + N_("Nature Magic"), + // TRANSLATORS: magic school + N_("Astral Magic") +}; + +class TargetTypeModel final : public gcn::ListModel +{ +public: + ~TargetTypeModel() + { } + + int getNumberOfElements() override + { + return 3; + } + + std::string getElementAt(int i) override + { + if (i >= getNumberOfElements() || i < 0) + return "???"; + return TARGET_TYPE_TEXT[i]; + } +}; + +class MagicSchoolModel final : public gcn::ListModel +{ +public: + ~MagicSchoolModel() + { } + + int getNumberOfElements() override + { + return 6; + } + + std::string getElementAt(int i) override + { + if (i >= getNumberOfElements() || i < 0) + return "???"; + return MAGIC_SCHOOL_TEXT[i]; + } +}; + +TextCommandEditor::TextCommandEditor(TextCommand *const command) : + // TRANSLATORS: command editor name + Window(_("Command Editor"), false, nullptr, "commandeditor.xml"), + gcn::ActionListener(), + mIsMagicCommand(command->getCommandType() == TEXT_COMMAND_MAGIC), + mCommand(command), + // TRANSLATORS: command editor button + mIsMagic(new RadioButton(this, _("magic"), "magic", mIsMagicCommand)), + // TRANSLATORS: command editor button + mIsOther(new RadioButton(this, _("other"), "magic", !mIsMagicCommand)), + // TRANSLATORS: command editor label + mSymbolLabel(new Label(this, _("Symbol:"))), + mSymbolTextField(new TextField(this)), + // TRANSLATORS: command editor label + mCommandLabel(new Label(this, _("Command:"))), + mCommandTextField(new TextField(this)), + // TRANSLATORS: command editor label + mCommentLabel(new Label(this, _("Comment:"))), + mCommentTextField(new TextField(this)), + mTargetTypeModel(new TargetTypeModel), + // TRANSLATORS: command editor label + mTypeLabel(new Label(this, _("Target Type:"))), + mTypeDropDown(new DropDown(this, mTargetTypeModel)), + mIconsModal(new IconsModal), + // TRANSLATORS: command editor label + mIconLabel(new Label(this, _("Icon:"))), + mIconDropDown(new DropDown(this, mIconsModal)), + // TRANSLATORS: command editor label + mManaLabel(new Label(this, _("Mana:"))), + mManaField(new IntTextField(this, 0)), + // TRANSLATORS: command editor label + mMagicLvlLabel(new Label(this, _("Magic level:"))), + mMagicLvlField(new IntTextField(this, 0)), + mMagicSchoolModel(new MagicSchoolModel), + // TRANSLATORS: command editor label + mSchoolLabel(new Label(this, _("Magic School:"))), + mSchoolDropDown(new DropDown(this, mMagicSchoolModel)), + // TRANSLATORS: command editor label + mSchoolLvlLabel(new Label(this, _("School level:"))), + mSchoolLvlField(new IntTextField(this, 0)), + // TRANSLATORS: command editor button + mCancelButton(new Button(this, _("Cancel"), "cancel", this)), + // TRANSLATORS: command editor button + mSaveButton(new Button(this, _("Save"), "save", this)), + // TRANSLATORS: command editor button + mDeleteButton(new Button(this, _("Delete"), "delete", this)), + mEnabledKeyboard(keyboard.isEnabled()) +{ + const int w = 350; + const int h = 370; + + keyboard.setEnabled(false); + + setWindowName("TextCommandEditor"); + setDefaultSize(w, h, ImageRect::CENTER); + + mIsMagic->setActionEventId("magic"); + mIsMagic->addActionListener(this); + + mIsOther->setActionEventId("other"); + mIsOther->addActionListener(this); + + mManaField->setRange(0, 500); + mManaField->setWidth(20); + + mTypeDropDown->setActionEventId("type"); + mTypeDropDown->addActionListener(this); + + mIconDropDown->setActionEventId("icon"); + mIconDropDown->addActionListener(this); + mIconDropDown->setSelectedString(mCommand->getIcon()); + + mMagicLvlField->setRange(0, 5); + mMagicLvlField->setWidth(20); + + mSchoolDropDown->setActionEventId("school"); + mSchoolDropDown->addActionListener(this); + mSchoolDropDown->setSelected(0); + + mSchoolLvlField->setRange(0, 5); + mSchoolLvlField->setWidth(20); + + mSaveButton->adjustSize(); + mCancelButton->adjustSize(); + mDeleteButton->adjustSize(); + + if (command->getCommandType() == TEXT_COMMAND_MAGIC) + showControls(true); + else + showControls(false); + + mSymbolTextField->setText(command->getSymbol()); + mCommandTextField->setText(command->getCommand()); + mCommentTextField->setText(command->getComment()); + mManaField->setValue(command->getMana()); + mTypeDropDown->setSelected(command->getTargetType()); + mMagicLvlField->setValue(command->getBaseLvl()); + mSchoolDropDown->setSelected(command->getSchool() - MAGIC_START_ID); + mSchoolLvlField->setValue(command->getSchoolLvl()); + + ContainerPlacer placer; + placer = getPlacer(0, 0); + + placer(0, 0, mIsMagic, 1); + placer(2, 0, mIsOther, 1); + placer(0, 1, mSymbolLabel, 2).setPadding(3); + placer(2, 1, mSymbolTextField, 3).setPadding(3); + placer(0, 2, mCommandLabel, 2).setPadding(3); + placer(2, 2, mCommandTextField, 4).setPadding(3); + + placer(0, 3, mCommentLabel, 2).setPadding(3); + placer(2, 3, mCommentTextField, 4).setPadding(3); + + placer(0, 4, mTypeLabel, 2).setPadding(3); + placer(2, 4, mTypeDropDown, 3).setPadding(3); + + placer(0, 5, mIconLabel, 2).setPadding(3); + placer(2, 5, mIconDropDown, 3).setPadding(3); + + placer(0, 6, mManaLabel, 2).setPadding(3); + placer(2, 6, mManaField, 3).setPadding(3); + placer(0, 7, mMagicLvlLabel, 2).setPadding(3); + placer(2, 7, mMagicLvlField, 3).setPadding(3); + + placer(0, 8, mSchoolLabel, 2).setPadding(3); + placer(2, 8, mSchoolDropDown, 3).setPadding(3); + placer(0, 9, mSchoolLvlLabel, 2).setPadding(3); + placer(2, 9, mSchoolLvlField, 3).setPadding(3); + + placer(0, 10, mSaveButton, 2).setPadding(3); + placer(2, 10, mCancelButton, 2).setPadding(3); + placer(4, 10, mDeleteButton, 2).setPadding(3); + + setWidth(w); + setHeight(h); + + reflowLayout(w); + + center(); + + enableVisibleSound(true); + setVisible(true); +} + +TextCommandEditor::~TextCommandEditor() +{ + delete mIconsModal; + mIconsModal = nullptr; + delete mTargetTypeModel; + mTargetTypeModel = nullptr; + delete mMagicSchoolModel; + mMagicSchoolModel = nullptr; +} + +void TextCommandEditor::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "magic") + { + mIsMagicCommand = true; + showControls(true); + } + else if (eventId == "other") + { + mIsMagicCommand = false; + showControls(false); + } + else if (eventId == "save") + { + save(); + scheduleDelete(); + } + else if (eventId == "cancel") + { + scheduleDelete(); + } + else if (eventId == "delete") + { + deleteCommand(); + scheduleDelete(); + } +} + +void TextCommandEditor::showControls(const bool show) +{ + mManaField->setVisible(show); + mManaLabel->setVisible(show); + mMagicLvlLabel->setVisible(show); + mMagicLvlField->setVisible(show); + mSchoolLabel->setVisible(show); + mSchoolDropDown->setVisible(show); + mSchoolLvlLabel->setVisible(show); + mSchoolLvlField->setVisible(show); +} + +void TextCommandEditor::scheduleDelete() +{ + keyboard.setEnabled(mEnabledKeyboard); + Window::scheduleDelete(); +} + +void TextCommandEditor::save() +{ + if (mIsMagicCommand) + mCommand->setCommandType(TEXT_COMMAND_MAGIC); + else + mCommand->setCommandType(TEXT_COMMAND_TEXT); + + mCommand->setSymbol(mSymbolTextField->getText()); + mCommand->setCommand(mCommandTextField->getText()); + mCommand->setComment(mCommentTextField->getText()); + mCommand->setMana(mManaField->getValue()); + mCommand->setTargetType( + static_cast(mTypeDropDown->getSelected())); + mCommand->setIcon(mIconDropDown->getSelectedString()); + mCommand->setBaseLvl(mMagicLvlField->getValue()); + mCommand->setSchool(static_cast( + mSchoolDropDown->getSelected() + MAGIC_START_ID)); + mCommand->setSchoolLvl(mSchoolLvlField->getValue()); + if (spellManager) + spellManager->save(); +} + +void TextCommandEditor::deleteCommand() +{ + mCommand->setCommandType(TEXT_COMMAND_TEXT); + mCommand->setSymbol(""); + mCommand->setCommand(""); + mCommand->setComment(""); + mCommand->setMana(0); + mCommand->setTargetType(NOTARGET); + mCommand->setIcon(""); + mCommand->setBaseLvl(0); + mCommand->setSchool(SKILL_MAGIC); + mCommand->setSchoolLvl(0); + if (spellManager) + spellManager->save(); +} diff --git a/src/gui/windows/textcommandeditor.h b/src/gui/windows/textcommandeditor.h new file mode 100644 index 000000000..610b014d5 --- /dev/null +++ b/src/gui/windows/textcommandeditor.h @@ -0,0 +1,103 @@ +/* + * The ManaPlus Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 Andrei Karas + * Copyright (C) 2011-2013 The ManaPlus developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_TEXTCOMMANDEDITOR_H +#define GUI_TEXTCOMMANDEDITOR_H + +#include "gui/widgets/window.h" + +#include + +class Button; +class DropDown; +class IconsModal; +class IntTextField; +class Label; +class MagicSchoolModel; +class RadioButton; +class TargetTypeModel; +class TextCommand; +class TextField; + +class TextCommandEditor final : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor. + */ + explicit TextCommandEditor(TextCommand *const command); + + A_DELETE_COPY(TextCommandEditor) + + /** + * Destructor. + */ + ~TextCommandEditor(); + + void action(const gcn::ActionEvent &event) override; + + void scheduleDelete() override; + + private: + void showControls(const bool show); + + void save(); + + void deleteCommand(); + + bool mIsMagicCommand; + TextCommand *mCommand; + + RadioButton *mIsMagic; + RadioButton *mIsOther; + Label *mSymbolLabel; + TextField *mSymbolTextField; + Label *mCommandLabel; + TextField *mCommandTextField; + + Label *mCommentLabel; + TextField *mCommentTextField; + + TargetTypeModel *mTargetTypeModel; + Label *mTypeLabel; + DropDown *mTypeDropDown; + IconsModal *mIconsModal; + Label *mIconLabel; + DropDown *mIconDropDown; + Label *mManaLabel; + IntTextField *mManaField; + Label *mMagicLvlLabel; + IntTextField *mMagicLvlField; + MagicSchoolModel *mMagicSchoolModel; + Label *mSchoolLabel; + DropDown *mSchoolDropDown; + Label *mSchoolLvlLabel; + IntTextField *mSchoolLvlField; + + Button *mCancelButton; + Button *mSaveButton; + Button *mDeleteButton; + + bool mEnabledKeyboard; +}; + +#endif // GUI_TEXTCOMMANDEDITOR_H diff --git a/src/gui/windows/textdialog.cpp b/src/gui/windows/textdialog.cpp new file mode 100644 index 000000000..3f62cef08 --- /dev/null +++ b/src/gui/windows/textdialog.cpp @@ -0,0 +1,131 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/textdialog.h" + +#include "input/keyboardconfig.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/label.h" +#include "gui/widgets/passwordfield.h" + +#include "utils/gettext.h" + +#include + +#include "debug.h" + +int TextDialog::instances = 0; + +TextDialog::TextDialog(const std::string &title, const std::string &msg, + Window *const parent, const bool isPassword): + Window(title, true, parent, "textdialog.xml"), + gcn::ActionListener(), + mTextField(nullptr), + mPasswordField(nullptr), + // TRANSLATORS: text dialog button + mOkButton(new Button(this, _("OK"), "OK", this)), + mEnabledKeyboard(keyboard.isEnabled()) +{ + keyboard.setEnabled(false); + + Label *const textLabel = new Label(this, msg); + // TRANSLATORS: text dialog button + Button *const cancelButton = new Button(this, _("Cancel"), "CANCEL", this); + + place(0, 0, textLabel, 4); + if (isPassword) + { + mPasswordField = new PasswordField(this); + place(0, 1, mPasswordField, 4); + } + else + { + mTextField = new TextField(this); + place(0, 1, mTextField, 4); + } + place(2, 2, mOkButton); + place(3, 2, cancelButton); + + const gcn::Font *const font = getFont(); + if (font) + { + int width = font->getWidth(title); + if (width < textLabel->getWidth()) + width = textLabel->getWidth(); + reflowLayout(static_cast(width + 20)); + } + else + { + reflowLayout(static_cast(textLabel->getWidth() + 20)); + } + + if (getParent()) + { + setLocationRelativeTo(getParent()); + getParent()->moveToTop(this); + } + setVisible(true); + requestModalFocus(); + if (isPassword) + mPasswordField->requestFocus(); + else + mTextField->requestFocus(); + + instances++; +} + +TextDialog::~TextDialog() +{ + instances--; +} + +void TextDialog::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "CANCEL") + setActionEventId("~" + getActionEventId()); + + distributeActionEvent(); + close(); +} + +const std::string &TextDialog::getText() const +{ + if (mTextField) + return mTextField->getText(); + else + return mPasswordField->getText(); +} + +void TextDialog::setText(const std::string &text) +{ + if (mTextField) + mTextField->setText(text); + else + mPasswordField->setText(text); +} + +void TextDialog::close() +{ + keyboard.setEnabled(mEnabledKeyboard); + scheduleDelete(); +} diff --git a/src/gui/windows/textdialog.h b/src/gui/windows/textdialog.h new file mode 100644 index 000000000..9f9292ef6 --- /dev/null +++ b/src/gui/windows/textdialog.h @@ -0,0 +1,80 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_TEXTDIALOG_H +#define GUI_TEXTDIALOG_H + +#include "gui/widgets/window.h" + +#include + +class Button; +class PasswordField; +class TextField; + +/** +* An option dialog. + * + * \ingroup GUI + */ +class TextDialog final : public Window, public gcn::ActionListener +{ +public: + /** + * Constructor. + * + * @see Window::Window + */ + TextDialog(const std::string &title, const std::string &msg, + Window *const parent = nullptr, const bool isPassword = false); + + A_DELETE_COPY(TextDialog) + + ~TextDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + /** + * Get the text in the textfield + */ + const std::string &getText() const A_WARN_UNUSED; + + void setText(const std::string &text); + + static bool isActive() A_WARN_UNUSED + { return instances; } + + void close() override; + +private: + static int instances; + + TextField *mTextField; + PasswordField *mPasswordField; + Button *mOkButton; + bool mEnabledKeyboard; +}; + +#endif // GUI_TEXTDIALOG_H diff --git a/src/gui/windows/tradewindow.cpp b/src/gui/windows/tradewindow.cpp new file mode 100644 index 000000000..bd3bf088f --- /dev/null +++ b/src/gui/windows/tradewindow.cpp @@ -0,0 +1,486 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/tradewindow.h" + +#include "configuration.h" +#include "inventory.h" +#include "item.h" +#include "units.h" + +#include "being/localplayer.h" +#include "being/playerinfo.h" +#include "being/playerrelations.h" + +#include "gui/gui.h" +#include "gui/sdlfont.h" + +#include "gui/windows/inventorywindow.h" +#include "gui/windows/itemamountwindow.h" +#include "gui/windows/setup.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/chattab.h" +#include "gui/widgets/itemcontainer.h" +#include "gui/widgets/label.h" +#include "gui/widgets/scrollarea.h" +#include "gui/widgets/textfield.h" +#include "gui/widgets/layout.h" + +#include "net/net.h" +#include "net/tradehandler.h" + +#include "utils/gettext.h" + +#include + +#include "debug.h" + +// TRANSLATORS: trade window button +#define CAPTION_PROPOSE _("Propose trade") +// TRANSLATORS: trade window button +#define CAPTION_CONFIRMED _("Confirmed. Waiting...") +// TRANSLATORS: trade window button +#define CAPTION_ACCEPT _("Agree trade") +// TRANSLATORS: trade window button +#define CAPTION_ACCEPTED _("Agreed. Waiting...") + +TradeWindow::TradeWindow(): + // TRANSLATORS: trade window caption + Window(_("Trade: You"), false, nullptr, "trade.xml"), + gcn::ActionListener(), + gcn::SelectionListener(), + mMyInventory(new Inventory(Inventory::TRADE)), + mPartnerInventory(new Inventory(Inventory::TRADE)), + mMyItemContainer(new ItemContainer(this, mMyInventory.get())), + mPartnerItemContainer(new ItemContainer(this, mPartnerInventory.get())), + // TRANSLATORS: trade window money label + mMoneyLabel(new Label(this, strprintf(_("You get %s"), ""))), + // TRANSLATORS: trade window button + mAddButton(new Button(this, _("Add"), "add", this)), + mOkButton(new Button(this, "", "", this)), // Will be filled in later + // TRANSLATORS: trade window money change button + mMoneyChangeButton(new Button(this, _("Change"), "money", this)), + mMoneyField(new TextField(this)), + mStatus(PROPOSING), + mAutoAddItem(nullptr), + mAutoAddToNick(""), + mGotMoney(0), + mGotMaxMoney(0), + mAutoMoney(0), + mAutoAddAmount(0), + mOkOther(false), + mOkMe(false) +{ + setWindowName("Trade"); + setResizable(true); + setCloseButton(true); + setStickyButtonLock(true); + setDefaultSize(386, 180, ImageRect::CENTER); + setMinWidth(310); + setMinHeight(180); + + if (setupWindow) + setupWindow->registerWindowForReset(this); + + const gcn::Font *const fnt = mOkButton->getFont(); + int width = std::max(fnt->getWidth(CAPTION_PROPOSE), + fnt->getWidth(CAPTION_CONFIRMED)); + width = std::max(width, fnt->getWidth(CAPTION_ACCEPT)); + width = std::max(width, fnt->getWidth(CAPTION_ACCEPTED)); + + mOkButton->setWidth(8 + width); + + mMyItemContainer->addSelectionListener(this); + + ScrollArea *const myScroll = new ScrollArea(mMyItemContainer, + true, "trade_background.xml"); + myScroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); + + mPartnerItemContainer->addSelectionListener(this); + + ScrollArea *const partnerScroll = new ScrollArea(mPartnerItemContainer, + true, "trade_background.xml"); + partnerScroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); + + // TRANSLATORS: trade window money label + Label *const moneyLabel2 = new Label(this, _("You give:")); + + mMoneyField->setWidth(40); + + place(1, 0, mMoneyLabel); + place(0, 1, myScroll).setPadding(3); + place(1, 1, partnerScroll).setPadding(3); + ContainerPlacer placer; + placer = getPlacer(0, 0); + placer(0, 0, moneyLabel2); + placer(1, 0, mMoneyField, 2); + placer(3, 0, mMoneyChangeButton).setHAlign(LayoutCell::LEFT); + placer = getPlacer(0, 2); + placer(0, 0, mAddButton); + placer(1, 0, mOkButton); + Layout &layout = getLayout(); + layout.extend(0, 2, 2, 1); + layout.setRowHeight(1, Layout::AUTO_SET); + layout.setRowHeight(2, 0); + layout.setColWidth(0, Layout::AUTO_SET); + layout.setColWidth(1, Layout::AUTO_SET); + + loadWindowState(); + enableVisibleSound(true); + + reset(); +} + +TradeWindow::~TradeWindow() +{ +} + +void TradeWindow::setMoney(const int amount) +{ + if (amount < 0 || amount < mGotMaxMoney) + { + if (config.getBoolValue("securetrades")) + { + close(); + return; + } + else + { + mMoneyLabel->setForegroundColorAll(getThemeColor( + static_cast(Theme::WARNING)), getThemeColor( + static_cast(Theme::WARNING_OUTLINE))); + } + } + else + { + mMoneyLabel->setForegroundColorAll(getThemeColor( + static_cast(Theme::LABEL)), getThemeColor( + static_cast(Theme::LABEL_OUTLINE))); + mGotMaxMoney = amount; + } + + mGotMoney = amount; + // TRANSLATORS: trade window money label + mMoneyLabel->setCaption(strprintf(_("You get %s"), + Units::formatCurrency(amount).c_str())); + mMoneyLabel->adjustSize(); +} + +void TradeWindow::addItem(const int id, const bool own, const int quantity, + const int refine, const unsigned char color) const +{ + if (own) + mMyInventory->addItem(id, quantity, refine, color); + else + mPartnerInventory->addItem(id, quantity, refine, color); +} + +void TradeWindow::addItem2(const int id, const bool own, const int quantity, + const int refine, const unsigned char color, + const bool equipment) const +{ + if (own) + mMyInventory->addItem(id, quantity, refine, color, equipment); + else + mPartnerInventory->addItem(id, quantity, refine, color, equipment); +} + +void TradeWindow::changeQuantity(const int index, const bool own, + const int quantity) const +{ + Item *item; + if (own) + item = mMyInventory->getItem(index); + else + item = mPartnerInventory->getItem(index); + if (item) + item->setQuantity(quantity); +} + +void TradeWindow::increaseQuantity(const int index, const bool own, + const int quantity) const +{ + Item *item; + if (own) + item = mMyInventory->getItem(index); + else + item = mPartnerInventory->getItem(index); + if (item) + item->increaseQuantity(quantity); +} + +void TradeWindow::reset() +{ + mMyInventory->clear(); + mPartnerInventory->clear(); + mOkOther = false; + mOkMe = false; + setMoney(0); + mMoneyField->setEnabled(true); + mMoneyField->setText(""); + mMoneyLabel->setForegroundColorAll(getThemeColor( + static_cast(Theme::LABEL)), getThemeColor( + static_cast(Theme::LABEL_OUTLINE))); + mAddButton->setEnabled(true); + mMoneyChangeButton->setEnabled(true); + mGotMoney = 0; + mGotMaxMoney = 0; + setStatus(PREPARING); +} + +void TradeWindow::receivedOk(const bool own) +{ + if (own) + mOkMe = true; + else + mOkOther = true; + + if (mOkMe && mOkOther) + setStatus(ACCEPTING); +} + +void TradeWindow::tradeItem(const Item *const item, const int quantity, + const bool check) const +{ + if (check && !checkItem(item)) + return; + + Net::getTradeHandler()->addItem(item, quantity); +} + +void TradeWindow::valueChanged(const gcn::SelectionEvent &event) +{ + if (!mMyItemContainer || !mPartnerItemContainer) + return; + + /* If an item is selected in one container, make sure no item is selected + * in the other container. + */ + if (event.getSource() == mMyItemContainer && + mMyItemContainer->getSelectedItem()) + { + mPartnerItemContainer->selectNone(); + } + else if (mPartnerItemContainer->getSelectedItem()) + { + mMyItemContainer->selectNone(); + } +} + +void TradeWindow::setStatus(const Status s) +{ + if (s == mStatus) + return; + mStatus = s; + + switch (s) + { + case PREPARING: + mOkButton->setCaption(CAPTION_PROPOSE); + mOkButton->setActionEventId("ok"); + break; + case PROPOSING: + mOkButton->setCaption(CAPTION_CONFIRMED); + mOkButton->setActionEventId(""); + break; + case ACCEPTING: + mOkButton->setCaption(CAPTION_ACCEPT); + mOkButton->setActionEventId("trade"); + break; + case ACCEPTED: + mOkButton->setCaption(CAPTION_ACCEPTED); + mOkButton->setActionEventId(""); + break; + default: + break; + } + + mOkButton->setEnabled((s != PROPOSING && s != ACCEPTED)); +} + +void TradeWindow::action(const gcn::ActionEvent &event) +{ + if (!inventoryWindow) + return; + + Item *const item = inventoryWindow->getSelectedItem(); + const std::string &eventId = event.getId(); + + if (eventId == "add") + { + if (mStatus != PREPARING) + return; + + if (!inventoryWindow->isWindowVisible()) + { + inventoryWindow->setVisible(true); + return; + } + + if (!item) + return; + + if (mMyInventory->getFreeSlot() == -1) + return; + + + if (!checkItem(item)) + return; + + // Choose amount of items to trade + ItemAmountWindow::showWindow(ItemAmountWindow::TradeAdd, this, item); + + setStatus(PREPARING); + } + else if (eventId == "cancel") + { + setVisible(false); + reset(); + PlayerInfo::setTrading(false); + Net::getTradeHandler()->cancel(); + } + else if (eventId == "ok") + { + mMoneyField->setEnabled(false); + mAddButton->setEnabled(false); + mMoneyChangeButton->setEnabled(false); + receivedOk(true); + setStatus(PROPOSING); + Net::getTradeHandler()->confirm(); + } + else if (eventId == "trade") + { + receivedOk(true); + setStatus(ACCEPTED); + Net::getTradeHandler()->finish(); + } + else if (eventId == "money") + { + if (mStatus != PREPARING) + return; + + int v = atoi(mMoneyField->getText().c_str()); + const int curMoney = PlayerInfo::getAttribute(PlayerInfo::MONEY); + if (v > curMoney) + { + if (localChatTab) + { + // TRANSLATORS: trade error + localChatTab->chatLog(_("You don't have enough money."), + BY_SERVER); + } + v = curMoney; + } + Net::getTradeHandler()->setMoney(v); + mMoneyField->setText(strprintf("%d", v)); + } +} + +void TradeWindow::close() +{ + Net::getTradeHandler()->cancel(); + clear(); +} + +void TradeWindow::clear() +{ + mAutoAddItem = nullptr; + mAutoAddToNick.clear(); + mAutoMoney = 0; + mAutoAddAmount = 0; + mGotMoney = 0; + mGotMaxMoney = 0; + mMoneyLabel->setForegroundColorAll(getThemeColor( + static_cast(Theme::LABEL)), getThemeColor( + static_cast(Theme::LABEL_OUTLINE))); +} + +void TradeWindow::addAutoItem(const std::string &nick, Item* const item, + const int amount) +{ + mAutoAddToNick = nick; + mAutoAddItem = item; + mAutoAddAmount = amount; +} + +void TradeWindow::addAutoMoney(const std::string &nick, const int money) +{ + mAutoAddToNick = nick; + mAutoMoney = money; +} + +void TradeWindow::initTrade(const std::string &nick) +{ + if (!player_node) + return; + + if (!mAutoAddToNick.empty() && mAutoAddToNick == nick) + { + if (mAutoAddItem && mAutoAddItem->getQuantity()) + { + const Inventory *const inv = PlayerInfo::getInventory(); + if (inv) + { + Item *const item = inv->findItem(mAutoAddItem->getId(), + mAutoAddItem->getColor()); + if (item) + tradeItem(item, mAutoAddItem->getQuantity()); + } + } + if (mAutoMoney) + { + Net::getTradeHandler()->setMoney(mAutoMoney); + mMoneyField->setText(strprintf("%d", mAutoMoney)); + } + } + clear(); + if (!player_relations.isGoodName(nick)) + setCaptionFont(gui->getSecureFont()); +} + +bool TradeWindow::checkItem(const Item *const item) const +{ + const int itemId = item->getId(); + if (PlayerInfo::isItemProtected(itemId)) + return false; + const Item *const tItem = mMyInventory->findItem( + itemId, item->getColor()); + + if (tItem && (tItem->getQuantity() > 1 + || item->getQuantity() > 1)) + { + if (localChatTab) + { + // TRANSLATORS: trade error + localChatTab->chatLog(_("Failed adding item. You can not " + "overlap one kind of item on the window."), BY_SERVER); + } + return false; + } + return true; +} + +bool TradeWindow::isInpupFocused() const +{ + return (mMoneyField && mMoneyField->isFocused()); +} diff --git a/src/gui/windows/tradewindow.h b/src/gui/windows/tradewindow.h new file mode 100644 index 000000000..df6d8a80a --- /dev/null +++ b/src/gui/windows/tradewindow.h @@ -0,0 +1,187 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_TRADEWINDOW_H +#define GUI_TRADEWINDOW_H + +#include "gui/widgets/window.h" + +#include +#include + +#include + +class Button; +class Inventory; +class Item; +class ItemContainer; +class Label; +class TextField; + +/** + * Trade dialog. + * + * \ingroup Interface + */ +class TradeWindow final : public Window, + private gcn::ActionListener, + private gcn::SelectionListener +{ + public: + /** + * Constructor. + */ + TradeWindow(); + + A_DELETE_COPY(TradeWindow) + + /** + * Destructor. + */ + ~TradeWindow(); + + /** + * Displays expected money in the trade window. + */ + void setMoney(const int quantity); + + /** + * Add an item to the trade window. + */ + void addItem(const int id, const bool own, const int quantity, + const int refine, const unsigned char color) const; + + /** + * Reset both item containers + */ + void reset(); + + /** + * Add an item to the trade window. + */ + void addItem2(const int id, const bool own, const int quantity, + const int refine, const unsigned char color, + const bool equipment) const; + + /** + * Change quantity of an item. + */ + void changeQuantity(const int index, const bool own, + const int quantity) const; + + /** + * Increase quantity of an item. + */ + void increaseQuantity(const int index, const bool own, + const int quantity) const; + + /** + * Player received ok message from server + */ + void receivedOk(const bool own); + + /** + * Send trade packet. + */ + void tradeItem(const Item *const item, const int quantity, + const bool check = false) const; + + /** + * Updates the labels and makes sure only one item is selected in + * either my inventory or partner inventory. + */ + void valueChanged(const gcn::SelectionEvent &event) override; + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + /** + * Closes the Trade Window, as well as telling the server that the + * window has been closed. + */ + void close() override; + + /** + * Clear auto trade items. + */ + void clear(); + + /** + * Add item what will be added to trade. + */ + void addAutoItem(const std::string &nick, Item *const item, + const int amount); + + void addAutoMoney(const std::string &nick, const int money); + + void initTrade(const std::string &nick); + + std::string getAutoTradeNick() const A_WARN_UNUSED + { return mAutoAddToNick; } + + bool checkItem(const Item *const item) const A_WARN_UNUSED; + + bool isInpupFocused() const A_WARN_UNUSED; + + private: + enum Status + { + PREPARING = 0, /**< Players are adding items. (1) */ + PROPOSING, /**< Local player has confirmed the trade. (1) */ + ACCEPTING, /**< Accepting the trade. (2) */ + ACCEPTED /**< Local player has accepted the trade. */ + }; + + /** + * Sets the current status of the trade. + */ + void setStatus(const Status s); + + typedef const std::auto_ptr InventoryPtr; + InventoryPtr mMyInventory; + InventoryPtr mPartnerInventory; + + ItemContainer *mMyItemContainer; + ItemContainer *mPartnerItemContainer; + + Label *mMoneyLabel; + Button *mAddButton; + Button *mOkButton; + Button *mMoneyChangeButton; + TextField *mMoneyField; + + Status mStatus; + Item* mAutoAddItem; + std::string mAutoAddToNick; + int mGotMoney; + int mGotMaxMoney; + int mAutoMoney; + int mAutoAddAmount; + bool mOkOther; + bool mOkMe; +}; + +extern TradeWindow *tradeWindow; + +#endif // GUI_TRADEWINDOW_H diff --git a/src/gui/windows/unregisterdialog.cpp b/src/gui/windows/unregisterdialog.cpp new file mode 100644 index 000000000..9c445ebdd --- /dev/null +++ b/src/gui/windows/unregisterdialog.cpp @@ -0,0 +1,154 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/unregisterdialog.h" + +#include "client.h" + +#include "gui/windows/okdialog.h" +#include "gui/windows/registerdialog.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/label.h" +#include "gui/widgets/passwordfield.h" + +#include "net/logindata.h" +#include "net/loginhandler.h" +#include "net/net.h" + +#include "utils/gettext.h" + +#include +#include + +#include "debug.h" + +UnRegisterDialog::UnRegisterDialog(LoginData *const data) : + // TRANSLATORS: unregister dialog name + Window(_("Unregister"), true, nullptr, "unregister.xml"), + gcn::ActionListener(), + mLoginData(data), + mPasswordField(new PasswordField(this, mLoginData->password)), + // TRANSLATORS: unregister dialog. button. + mUnRegisterButton(new Button(this, _("Unregister"), "unregister", this)), + // TRANSLATORS: unregister dialog. button. + mCancelButton(new Button(this, _("Cancel"), "cancel", this)), + mWrongDataNoticeListener(new WrongDataNoticeListener) +{ + // TRANSLATORS: unregister dialog. label. + Label *const userLabel = new Label(this, strprintf(_("Name: %s"), + mLoginData->username.c_str())); + // TRANSLATORS: unregister dialog. label. + Label *const passwordLabel = new Label(this, _("Password:")); + + const int width = 210; + const int height = 80; + setContentSize(width, height); + + userLabel->setPosition(5, 5); + userLabel->setWidth(width - 5); + mPasswordField->setPosition( + 68, userLabel->getY() + userLabel->getHeight() + 7); + mPasswordField->setWidth(130); + + passwordLabel->setPosition(5, mPasswordField->getY() + 1); + + mCancelButton->setPosition( + width - 5 - mCancelButton->getWidth(), + height - 5 - mCancelButton->getHeight()); + mUnRegisterButton->setPosition( + mCancelButton->getX() - 5 - mUnRegisterButton->getWidth(), + mCancelButton->getY()); + + add(userLabel); + add(passwordLabel); + add(mPasswordField); + add(mUnRegisterButton); + add(mCancelButton); + + center(); + setVisible(true); + mPasswordField->requestFocus(); + mPasswordField->setActionEventId("cancel"); +} + +UnRegisterDialog::~UnRegisterDialog() +{ + delete mWrongDataNoticeListener; + mWrongDataNoticeListener = nullptr; +} + +void UnRegisterDialog::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "cancel") + { + client->setState(STATE_CHAR_SELECT); + } + else if (eventId == "unregister") + { + const std::string username = mLoginData->username.c_str(); + const std::string password = mPasswordField->getText(); + logger->log("UnregisterDialog::unregistered, Username is %s", + username.c_str()); + + std::stringstream errorMsg; + bool error = false; + + const unsigned int min = Net::getLoginHandler() + ->getMinPasswordLength(); + const unsigned int max = Net::getLoginHandler() + ->getMaxPasswordLength(); + + if (password.length() < min) + { + // TRANSLATORS: unregister dialog. error message. + errorMsg << strprintf(_("The password needs to be at least %u " + "characters long."), min); + error = true; + } + else if (password.length() > max) + { + // TRANSLATORS: unregister dialog. error message. + errorMsg << strprintf(_("The password needs to be less than " + "%u characters long."), max); + error = true; + } + + if (error) + { + mWrongDataNoticeListener->setTarget(this->mPasswordField); + + // TRANSLATORS: unregister dialog. error message. + OkDialog *const dlg = new OkDialog(_("Error"), + errorMsg.str(), DIALOG_ERROR); + dlg->addActionListener(mWrongDataNoticeListener); + } + else + { + // No errors detected, unregister the new user. + mUnRegisterButton->setEnabled(false); + mLoginData->password = password; + client->setState(STATE_UNREGISTER_ATTEMPT); + } + } +} diff --git a/src/gui/windows/unregisterdialog.h b/src/gui/windows/unregisterdialog.h new file mode 100644 index 000000000..de0da27bb --- /dev/null +++ b/src/gui/windows/unregisterdialog.h @@ -0,0 +1,70 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_UNREGISTERDIALOG_H +#define GUI_UNREGISTERDIALOG_H + +#include "gui/widgets/window.h" + +#include + +class Button; +class LoginData; +class TextField; +class WrongDataNoticeListener; + +/** + * The Unregister dialog. + * + * \ingroup Interface + */ +class UnRegisterDialog final : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor + * + * @see Window::Window + */ + explicit UnRegisterDialog(LoginData *const loginData); + + A_DELETE_COPY(UnRegisterDialog) + + ~UnRegisterDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + private: + LoginData *mLoginData; + + TextField *mPasswordField; + + Button *mUnRegisterButton; + Button *mCancelButton; + + WrongDataNoticeListener *mWrongDataNoticeListener; +}; + +#endif // GUI_UNREGISTERDIALOG_H diff --git a/src/gui/windows/updaterwindow.cpp b/src/gui/windows/updaterwindow.cpp new file mode 100644 index 000000000..d025f83b6 --- /dev/null +++ b/src/gui/windows/updaterwindow.cpp @@ -0,0 +1,943 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/updaterwindow.h" + +#include "client.h" +#include "configuration.h" + +#include "input/keydata.h" +#include "input/keyevent.h" + +#include "gui/widgets/browserbox.h" +#include "gui/widgets/button.h" +#include "gui/widgets/label.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/progressbar.h" +#include "gui/widgets/scrollarea.h" + +#include "net/logindata.h" + +#include "resources/resourcemanager.h" + +#include "utils/gettext.h" +#include "utils/mkdir.h" +#include "utils/paths.h" +#include "utils/process.h" + +#include + +#include + +#include "debug.h" + +const std::string xmlUpdateFile("resources.xml"); +const std::string txtUpdateFile("resources2.txt"); +const std::string updateServer2 + ("http://download.evolonline.org/manaplus/updates/"); + +/** + * Load the given file into a vector of updateFiles. + */ +static std::vector loadXMLFile(const std::string &fileName) +{ + std::vector files; + XML::Document doc(fileName, false); + const XmlNodePtr rootNode = doc.rootNode(); + + if (!rootNode || !xmlNameEqual(rootNode, "updates")) + { + logger->log("Error loading update file: %s", fileName.c_str()); + return files; + } + + for_each_xml_child_node(fileNode, rootNode) + { + if (!xmlNameEqual(fileNode, "update")) + continue; + + if (XML::getProperty(fileNode, "group", "default") != "default") + continue; + + UpdateFile file; + file.name = XML::getProperty(fileNode, "file", ""); + file.hash = XML::getProperty(fileNode, "hash", ""); + file.type = XML::getProperty(fileNode, "type", "data"); + file.desc = XML::getProperty(fileNode, "description", ""); + const std::string version = XML::getProperty( + fileNode, "version", ""); + if (!version.empty()) + { + if (version > CHECK_VERSION) + continue; + } + const std::string notVersion = XML::getProperty( + fileNode, "notVersion", ""); + if (!notVersion.empty()) + { + if (notVersion <= CHECK_VERSION) + continue; + } + if (XML::getProperty(fileNode, "required", "yes") == "yes") + file.required = true; + else + file.required = false; + + if (checkPath(file.name)) + files.push_back(file); + } + + return files; +} + +static std::vector loadTxtFile(const std::string &fileName) +{ + std::vector files; + std::ifstream fileHandler; + fileHandler.open(fileName.c_str(), std::ios::in); + + if (fileHandler.is_open()) + { + while (fileHandler.good()) + { + char name[256]; + char hash[50]; + fileHandler.getline(name, 256, ' '); + fileHandler.getline(hash, 50); + + UpdateFile thisFile; + thisFile.name = name; + thisFile.hash = hash; + thisFile.type = "data"; + thisFile.required = true; + thisFile.desc.clear(); + + if (!thisFile.name.empty() && checkPath(thisFile.name)) + files.push_back(thisFile); + } + } + else + { + logger->log("Error loading update file: %s", fileName.c_str()); + } + fileHandler.close(); + + return files; +} + +UpdaterWindow::UpdaterWindow(const std::string &updateHost, + const std::string &updatesDir, + const bool applyUpdates, + const int updateType): + // TRANSLATORS: updater window name + Window(_("Updating..."), false, nullptr, "update.xml"), + gcn::ActionListener(), + gcn::KeyListener(), + mDownloadStatus(UPDATE_NEWS), + mUpdateHost(updateHost), + mUpdatesDir(updatesDir), + mUpdatesDirReal(updatesDir), + mCurrentFile("news.txt"), + mNewLabelCaption(), + mDownloadProgress(0.0F), + mDownloadMutex(), + mCurrentChecksum(0), + mStoreInMemory(true), + mDownloadComplete(true), + mUserCancel(false), + mDownloadedBytes(0), + mMemoryBuffer(nullptr), + mDownload(nullptr), + mUpdateFiles(), + mTempUpdateFiles(), + mUpdateIndex(0), + mUpdateIndexOffset(0), + mLoadUpdates(applyUpdates), + mUpdateType(updateType), + // TRANSLATORS: updater window label + mLabel(new Label(this, _("Connecting..."))), + // TRANSLATORS: updater window button + mCancelButton(new Button(this, _("Cancel"), "cancel", this)), + // TRANSLATORS: updater window button + mPlayButton(new Button(this, _("Play"), "play", this)), + mProgressBar(new ProgressBar(this, 0.0, 310, 0)), + mBrowserBox(new BrowserBox(this)), + mScrollArea(new ScrollArea(mBrowserBox, true, "update_background.xml")), + mUpdateServerPath(mUpdateHost) +{ + setWindowName("UpdaterWindow"); + setResizable(true); + setDefaultSize(450, 400, ImageRect::CENTER); + setMinWidth(310); + setMinHeight(220); + + mProgressBar->setSmoothProgress(false); + mBrowserBox->setOpaque(false); + mBrowserBox->setLinkHandler(this); + mBrowserBox->setEnableKeys(true); + mBrowserBox->setEnableTabs(true); + mPlayButton->setEnabled(false); + + ContainerPlacer placer; + placer = getPlacer(0, 0); + + placer(0, 0, mScrollArea, 5, 3).setPadding(3); + placer(0, 3, mLabel, 5); + placer(0, 4, mProgressBar, 5); + placer(3, 5, mCancelButton); + placer(4, 5, mPlayButton); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + + addKeyListener(this); + + loadWindowState(); + setVisible(true); + mCancelButton->requestFocus(); + removeProtocol(mUpdateServerPath); + + download(); +} + +UpdaterWindow::~UpdaterWindow() +{ + if (mLoadUpdates) + loadUpdates(); + + if (mDownload) + { + mDownload->cancel(); + + delete mDownload; + mDownload = nullptr; + } + free(mMemoryBuffer); +} + +void UpdaterWindow::setProgress(const float p) +{ + // Do delayed progress bar update, since Guichan isn't thread-safe + MutexLocker lock(&mDownloadMutex); + mDownloadProgress = p; +} + +void UpdaterWindow::setLabel(const std::string &str) +{ + // Do delayed label text update, since Guichan isn't thread-safe + MutexLocker lock(&mDownloadMutex); + mNewLabelCaption = str; +} + +void UpdaterWindow::enable() +{ + mCancelButton->setEnabled(false); + mPlayButton->setEnabled(true); + mPlayButton->requestFocus(); + + if (mUpdateType & LoginData::Upd_Close) + client->setState(STATE_LOAD_DATA); +} + +void UpdaterWindow::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "cancel") + { + // Register the user cancel + mUserCancel = true; + // Skip the updating process + if (mDownloadStatus != UPDATE_COMPLETE) + { + mDownload->cancel(); + mDownloadStatus = UPDATE_ERROR; + } + } + else if (eventId == "play") + { + client->setState(STATE_LOAD_DATA); + } +} + +void UpdaterWindow::keyPressed(gcn::KeyEvent &keyEvent) +{ + const int actionId = static_cast(&keyEvent)->getActionId(); + if (actionId == static_cast(Input::KEY_GUI_CANCEL)) + { + action(gcn::ActionEvent(nullptr, mCancelButton->getActionEventId())); + client->setState(STATE_LOGIN); + } + else if (actionId == static_cast(Input::KEY_GUI_SELECT) + || actionId == static_cast(Input::KEY_GUI_SELECT2)) + { + if (mDownloadStatus == UPDATE_COMPLETE || + mDownloadStatus == UPDATE_ERROR) + { + action(gcn::ActionEvent(nullptr, mPlayButton->getActionEventId())); + } + else + { + action(gcn::ActionEvent(nullptr, + mCancelButton->getActionEventId())); + } + } +} + +void UpdaterWindow::loadNews() +{ + if (!mMemoryBuffer) + { + logger->log1("Couldn't load news"); + return; + } + + // Reallocate and include terminating 0 character + mMemoryBuffer = static_cast(realloc( + mMemoryBuffer, mDownloadedBytes + 1)); + + mMemoryBuffer[mDownloadedBytes] = '\0'; + mBrowserBox->clearRows(); + + std::string newsName = mUpdatesDir + "/local/help/news.txt"; + mkdir_r((mUpdatesDir + "/local/help/").c_str()); + bool firstLine(true); + std::ofstream file; + std::stringstream ss(mMemoryBuffer); + std::string line; + file.open(newsName.c_str(), std::ios::out); + while (std::getline(ss, line, '\n')) + { + if (firstLine) + { + firstLine = false; + const size_t i = line.find("##9 Latest client version: ##6"); + if (!i) + continue; + + if (file.is_open()) + file << line << std::endl; + mBrowserBox->addRow(line); + } + else + { + if (file.is_open()) + file << line << std::endl; + mBrowserBox->addRow(line); + } + } + + file.close(); + // Free the memory buffer now that we don't need it anymore + free(mMemoryBuffer); + mMemoryBuffer = nullptr; + mDownloadedBytes = 0; + + mScrollArea->setVerticalScrollAmount(0); +} + +void UpdaterWindow::loadPatch() +{ + if (!mMemoryBuffer) + { + logger->log1("Couldn't load patch"); + return; + } + + // Reallocate and include terminating 0 character + mMemoryBuffer = static_cast( + realloc(mMemoryBuffer, mDownloadedBytes + 1)); + mMemoryBuffer[mDownloadedBytes] = '\0'; + + std::string version; + + // Tokenize and add each line separately + char *line = strtok(mMemoryBuffer, "\n"); + if (line) + { + version = line; + if (serverVersion < 1) + { + line = strtok(nullptr, "\n"); + if (line) + { + mBrowserBox->addRow(strprintf("##9 Latest client version: " + "##6ManaPlus %s##0", line), true); + } + } + if (version > CHECK_VERSION) + { +#if defined(ANDROID) + mBrowserBox->addRow("", true); + mBrowserBox->addRow("##1You can download from [[@@" + "https://play.google.com/store/apps/details?id=org.evolonline" + ".beta.manaplus|Google Play@@]", true); + mBrowserBox->addRow("##1ManaPlus updated.", true); +#elif defined(WIN32) + mBrowserBox->addRow("", true); + mBrowserBox->addRow(" ##1[@@http://download.evolonline.org/" + "manaplus/download/manaplus-win32.exe|download here@@]", true); +#else + mBrowserBox->addRow("", true); + mBrowserBox->addRow(" ##1@@http://manaplus.org/|" + "http://manaplus.org/@@", true); + mBrowserBox->addRow("##1You can download it from", true); + mBrowserBox->addRow("##1ManaPlus updated.", true); +#endif + } + else + { + mBrowserBox->addRow("You have latest client version.", true); + } + } + + // Free the memory buffer now that we don't need it anymore + free(mMemoryBuffer); + mMemoryBuffer = nullptr; + mDownloadedBytes = 0; + + mScrollArea->setVerticalScrollAmount(0); +} + +int UpdaterWindow::updateProgress(void *ptr, DownloadStatus status, + size_t dt, size_t dn) +{ + UpdaterWindow *const uw = reinterpret_cast(ptr); + if (!uw) + return -1; + + if (status == DOWNLOAD_STATUS_COMPLETE) + { + uw->mDownloadComplete = true; + } + else if (status == DOWNLOAD_STATUS_ERROR || + status == DOWNLOAD_STATUS_CANCELLED) + { + if (uw->mDownloadStatus == UPDATE_COMPLETE) + { // ignoring error in last state (was UPDATE_PATCH) + uw->mDownloadStatus = UPDATE_COMPLETE; + uw->mDownloadComplete = true; + free(uw->mMemoryBuffer); + uw->mMemoryBuffer = nullptr; + } + else + { + uw->mDownloadStatus = UPDATE_ERROR; + } + } + + if (!dt) + dt = 1; + + float progress = static_cast(dn) / + static_cast(dt); + + if (progress != progress) + progress = 0.0F; // check for NaN + if (progress < 0.0F) + progress = 0.0F; // no idea how this could ever happen, + // but why not check for it anyway. + if (progress > 1.0F) + progress = 1.0F; + + uw->setLabel(std::string(uw->mCurrentFile).append(" (") + .append(toString(static_cast(progress * 100))).append("%)")); + + uw->setProgress(progress); + + if (client->getState() != STATE_UPDATE + || uw->mDownloadStatus == UPDATE_ERROR) + { + // If the action was canceled return an error code to stop the mThread + return -1; + } + + return 0; +} + +size_t UpdaterWindow::memoryWrite(void *ptr, size_t size, + size_t nmemb, void *stream) +{ + UpdaterWindow *const uw = reinterpret_cast(stream); + const size_t totalMem = size * nmemb; + uw->mMemoryBuffer = static_cast(realloc(uw->mMemoryBuffer, + uw->mDownloadedBytes + totalMem)); + if (uw->mMemoryBuffer) + { + memcpy(&(uw->mMemoryBuffer[uw->mDownloadedBytes]), ptr, totalMem); + uw->mDownloadedBytes += static_cast(totalMem); + } + + return totalMem; +} + +void UpdaterWindow::download() +{ + if (mDownload) + { + mDownload->cancel(); + delete mDownload; + } + if (mDownloadStatus == UPDATE_PATCH) + { + mDownload = new Net::Download(this, + "http://manaplus.org/update/" + mCurrentFile, + updateProgress, true); + } + else + { + mDownload = new Net::Download(this, std::string(mUpdateHost).append( + "/").append(mCurrentFile), updateProgress); + } + + if (mStoreInMemory) + { + mDownload->setWriteFunction(UpdaterWindow::memoryWrite); + } + else + { + if (mDownloadStatus == UPDATE_RESOURCES) + { + mDownload->setFile(std::string(mUpdatesDir).append("/").append( + mCurrentFile), mCurrentChecksum); + } + else + { + mDownload->setFile(std::string(mUpdatesDir).append( + "/").append(mCurrentFile)); + } + } + + if (mDownloadStatus != UPDATE_RESOURCES) + mDownload->noCache(); + + setLabel(mCurrentFile + " (0%)"); + mDownloadComplete = false; + + mDownload->start(); +} + +void UpdaterWindow::loadUpdates() +{ + const ResourceManager *const resman = ResourceManager::getInstance(); + if (mUpdateFiles.empty()) + { // updates not downloaded + mUpdateFiles = loadXMLFile(std::string(mUpdatesDir).append( + "/").append(xmlUpdateFile)); + if (mUpdateFiles.empty()) + { + logger->log("Warning this server does not have a" + " %s file falling back to %s", xmlUpdateFile.c_str(), + txtUpdateFile.c_str()); + mUpdateFiles = loadTxtFile(std::string(mUpdatesDir).append( + "/").append(txtUpdateFile)); + } + } + + std::string fixPath = mUpdatesDir + "/fix"; + const unsigned sz = static_cast(mUpdateFiles.size()); + for (mUpdateIndex = 0; mUpdateIndex < sz; mUpdateIndex++) + { + UpdaterWindow::addUpdateFile(resman, mUpdatesDir, fixPath, + mUpdateFiles[mUpdateIndex].name, false); + } + loadManaPlusUpdates(mUpdatesDir, resman); +} + +void UpdaterWindow::loadLocalUpdates(const std::string &dir) +{ + const ResourceManager *const resman = ResourceManager::getInstance(); + + std::vector updateFiles + = loadXMLFile(std::string(dir).append("/").append(xmlUpdateFile)); + + if (updateFiles.empty()) + { + logger->log("Warning this server does not have a" + " %s file falling back to %s", xmlUpdateFile.c_str(), + txtUpdateFile.c_str()); + updateFiles = loadTxtFile(std::string(dir).append( + "/").append(txtUpdateFile)); + } + + const std::string fixPath = dir + "/fix"; + for (unsigned int updateIndex = 0, sz = static_cast( + updateFiles.size()); updateIndex < sz; updateIndex ++) + { + UpdaterWindow::addUpdateFile(resman, dir, fixPath, + updateFiles[updateIndex].name, false); + } + loadManaPlusUpdates(dir, resman); +} + +void UpdaterWindow::unloadUpdates(const std::string &dir) +{ + const ResourceManager *const resman = ResourceManager::getInstance(); + std::vector updateFiles + = loadXMLFile(std::string(dir).append("/").append(xmlUpdateFile)); + + if (updateFiles.empty()) + { + updateFiles = loadTxtFile(std::string(dir).append( + "/").append(txtUpdateFile)); + } + + const std::string fixPath = dir + "/fix"; + for (unsigned int updateIndex = 0, sz = static_cast( + updateFiles.size()); updateIndex < sz; updateIndex ++) + { + UpdaterWindow::removeUpdateFile(resman, dir, fixPath, + updateFiles[updateIndex].name); + } + unloadManaPlusUpdates(dir, resman); +} + +void UpdaterWindow::loadManaPlusUpdates(const std::string &dir, + const ResourceManager *const resman) +{ + std::string fixPath = dir + "/fix"; + std::vector updateFiles + = loadXMLFile(std::string(fixPath).append("/").append(xmlUpdateFile)); + + for (unsigned int updateIndex = 0, sz = static_cast( + updateFiles.size()); updateIndex < sz; updateIndex ++) + { + std::string name = updateFiles[updateIndex].name; + if (strStartWith(name, "manaplus_")) + { + struct stat statbuf; + std::string file = std::string(fixPath).append("/").append(name); + if (!stat(file.c_str(), &statbuf)) + resman->addToSearchPath(file, false); + } + } +} + +void UpdaterWindow::unloadManaPlusUpdates(const std::string &dir, + const ResourceManager *const resman) +{ + const std::string fixPath = dir + "/fix"; + const std::vector updateFiles + = loadXMLFile(std::string(fixPath).append("/").append(xmlUpdateFile)); + + for (unsigned int updateIndex = 0, sz = static_cast( + updateFiles.size()); updateIndex < sz; updateIndex ++) + { + std::string name = updateFiles[updateIndex].name; + if (strStartWith(name, "manaplus_")) + { + struct stat statbuf; + const std::string file = std::string( + fixPath).append("/").append(name); + if (!stat(file.c_str(), &statbuf)) + resman->removeFromSearchPath(file); + } + } +} + +void UpdaterWindow::addUpdateFile(const ResourceManager *const resman, + const std::string &path, + const std::string &fixPath, + const std::string &file, + const bool append) +{ + const std::string tmpPath = std::string(path).append("/").append(file); + if (!append) + resman->addToSearchPath(tmpPath, append); + + const std::string fixFile = std::string(fixPath).append("/").append(file); + struct stat statbuf; + if (!stat(fixFile.c_str(), &statbuf)) + resman->addToSearchPath(fixFile, append); + + if (append) + resman->addToSearchPath(tmpPath, append); +} + +void UpdaterWindow::removeUpdateFile(const ResourceManager *const resman, + const std::string &path, + const std::string &fixPath, + const std::string &file) +{ + resman->removeFromSearchPath(std::string(path).append("/").append(file)); + const std::string fixFile = std::string(fixPath).append("/").append(file); + struct stat statbuf; + if (!stat(fixFile.c_str(), &statbuf)) + resman->removeFromSearchPath(fixFile); +} + +void UpdaterWindow::logic() +{ + BLOCK_START("UpdaterWindow::logic") + // Update Scroll logic + mScrollArea->logic(); + + // Synchronize label caption when necessary + { + MutexLocker lock(&mDownloadMutex); + + if (mLabel->getCaption() != mNewLabelCaption) + { + mLabel->setCaption(mNewLabelCaption); + mLabel->adjustSize(); + } + + mProgressBar->setProgress(mDownloadProgress); + if (mUpdateFiles.size() && mUpdateIndex <= mUpdateFiles.size()) + { + mProgressBar->setText(strprintf("%u/%u", mUpdateIndex + + mUpdateIndexOffset + 1, static_cast( + mUpdateFiles.size()) + static_cast( + mTempUpdateFiles.size()) + 1)); + } + else + { + mProgressBar->setText(""); + } + } + + switch (mDownloadStatus) + { + case UPDATE_ERROR: + mBrowserBox->addRow(""); + // TRANSLATORS: update message + mBrowserBox->addRow(_("##1 The update process is incomplete.")); + // TRANSLATORS: Continues "The update process is incomplete.". + mBrowserBox->addRow(_("##1 It is strongly recommended that")); + // TRANSLATORS: Begins "It is strongly recommended that". + mBrowserBox->addRow(_("##1 you try again later.")); + + mBrowserBox->addRow(mDownload->getError()); + mScrollArea->setVerticalScrollAmount( + mScrollArea->getVerticalMaxScroll()); + mDownloadStatus = UPDATE_COMPLETE; + break; + case UPDATE_NEWS: + if (mDownloadComplete) + { + // Parse current memory buffer as news and dispose of the data + loadNews(); + + mCurrentFile = xmlUpdateFile; + mStoreInMemory = false; + mDownloadStatus = UPDATE_LIST; + download(); // download() changes mDownloadComplete to false + } + break; + case UPDATE_PATCH: + if (mDownloadComplete) + { + // Parse current memory buffer as news and dispose of the data + loadPatch(); + + mUpdateHost = updateServer2 + mUpdateServerPath; + mUpdatesDir.append("/fix"); + mCurrentFile = xmlUpdateFile; + mStoreInMemory = false; + mDownloadStatus = UPDATE_LIST2; + download(); + } + break; + + case UPDATE_LIST: + if (mDownloadComplete) + { + if (mCurrentFile == xmlUpdateFile) + { + mUpdateFiles = loadXMLFile(std::string(mUpdatesDir).append( + "/").append(xmlUpdateFile)); + + if (mUpdateFiles.empty()) + { + logger->log("Warning this server does not have a %s" + " file falling back to %s", + xmlUpdateFile.c_str(), + txtUpdateFile.c_str()); + + // If the resources.xml file fails, + // fall back onto a older version + mCurrentFile = txtUpdateFile; + mStoreInMemory = false; + mDownloadStatus = UPDATE_LIST; + download(); + break; + } + } + else if (mCurrentFile == txtUpdateFile) + { + mUpdateFiles = loadTxtFile(std::string(mUpdatesDir).append( + "/").append(txtUpdateFile)); + } + mStoreInMemory = false; + mDownloadStatus = UPDATE_RESOURCES; + } + break; + case UPDATE_RESOURCES: + if (mDownloadComplete) + { + if (mUpdateIndex < mUpdateFiles.size()) + { + UpdateFile thisFile = mUpdateFiles[mUpdateIndex]; + if (!thisFile.required) + { + // This statement checks to see if the file type + // is music, and if download-music is true + // If it fails, this statement returns true, + // and results in not downloading the file + // Else it will ignore the break, + // and download the file. + + if (!(thisFile.type == "music" + && config.getBoolValue("download-music"))) + { + mUpdateIndex++; + break; + } + } + mCurrentFile = thisFile.name; + std::string checksum; + checksum = thisFile.hash; + std::stringstream ss(checksum); + ss >> std::hex >> mCurrentChecksum; + + std::ifstream temp((std::string(mUpdatesDir).append( + "/").append(mCurrentFile)).c_str()); + + if (!temp.is_open() || !validateFile(std::string( + mUpdatesDir).append("/").append(mCurrentFile), + mCurrentChecksum)) + { + temp.close(); + download(); + } + else + { + temp.close(); + logger->log("%s already here", mCurrentFile.c_str()); + } + mUpdateIndex++; + } + else + { + // Download of updates completed + mCurrentFile = "latest.txt"; + mStoreInMemory = true; + mDownloadStatus = UPDATE_PATCH; + download(); // download() changes + // mDownloadComplete to false + } + } + break; + case UPDATE_LIST2: + if (mDownloadComplete) + { + if (mCurrentFile == xmlUpdateFile) + { + mTempUpdateFiles = loadXMLFile(std::string( + mUpdatesDir).append("/").append(xmlUpdateFile)); + } + mUpdateIndexOffset = mUpdateIndex; + mUpdateIndex = 0; + mStoreInMemory = false; + mDownloadStatus = UPDATE_RESOURCES2; + download(); + } + break; + case UPDATE_RESOURCES2: + if (mDownloadComplete) + { + if (mUpdateIndex < mTempUpdateFiles.size()) + { + const UpdateFile thisFile = mTempUpdateFiles[mUpdateIndex]; + mCurrentFile = thisFile.name; + std::string checksum; + checksum = thisFile.hash; + std::stringstream ss(checksum); + ss >> std::hex >> mCurrentChecksum; + + std::ifstream temp((std::string(mUpdatesDir).append( + "/").append(mCurrentFile)).c_str()); + + if (!temp.is_open() || !validateFile(std::string( + mUpdatesDir).append("/").append(mCurrentFile), + mCurrentChecksum)) + { + temp.close(); + download(); + } + else + { + temp.close(); + logger->log("%s already here", mCurrentFile.c_str()); + } + mUpdateIndex++; + } + else + { + mUpdatesDir = mUpdatesDirReal; + mDownloadStatus = UPDATE_COMPLETE; + } + } + break; + case UPDATE_COMPLETE: + mUpdatesDir = mUpdatesDirReal; + enable(); + // TRANSLATORS: updater window label + setLabel(_("Completed")); + break; + case UPDATE_IDLE: + break; + default: + logger->log("UpdaterWindow::logic unknown status: " + + toString(static_cast(mDownloadStatus))); + break; + } + BLOCK_END("UpdaterWindow::logic") +} + +bool UpdaterWindow::validateFile(const std::string &filePath, + const unsigned long hash) +{ + FILE *const file = fopen(filePath.c_str(), "rb"); + if (!file) + return false; + + const unsigned long adler = Net::Download::fadler32(file); + fclose(file); + return adler == hash; +} + +unsigned long UpdaterWindow::getFileHash(const std::string &filePath) +{ + int size = 0; + char *const buf = static_cast(ResourceManager::loadFile( + filePath, size)); + if (!buf) + return 0; + return Net::Download::adlerBuffer(buf, size); +} + +void UpdaterWindow::handleLink(const std::string &link, + gcn::MouseEvent *event A_UNUSED) +{ + if (strStartWith(link, "http://") || strStartWith(link, "https://")) + openBrowser(link); +} diff --git a/src/gui/windows/updaterwindow.h b/src/gui/windows/updaterwindow.h new file mode 100644 index 000000000..e317e3f95 --- /dev/null +++ b/src/gui/windows/updaterwindow.h @@ -0,0 +1,258 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_UPDATERWINDOW_H +#define GUI_UPDATERWINDOW_H + +#include "gui/widgets/linkhandler.h" +#include "gui/widgets/window.h" + +#include "net/download.h" + +#include "utils/mutex.h" + +#include +#include + +#include +#include + +class BrowserBox; +class Button; +class Label; +class ProgressBar; +class ResourceManager; +class ScrollArea; + +struct UpdateFile final +{ + public: + UpdateFile() : + name(), + hash(), + type(), + desc(), + required(false) + { + } + std::string name; + std::string hash; + std::string type; + std::string desc; + bool required; +}; + +/** + * Update progress window GUI + * + * \ingroup GUI + */ +class UpdaterWindow final : public Window, + public gcn::ActionListener, + public LinkHandler, + public gcn::KeyListener +{ + public: + /** + * Constructor. + * + * @param updateHost Host where to get the updated files. + * @param updatesDir Directory where to store updates (should be absolute + * and already created). + * @param applyUpdates If true, the update window will pass the updates to teh + * resource manager + */ + UpdaterWindow(const std::string &updateHost, + const std::string &updatesDir, + const bool applyUpdates, const int updateType); + + A_DELETE_COPY(UpdaterWindow) + + /** + * Destructor + */ + ~UpdaterWindow(); + + /** + * Set's progress bar status + */ + void setProgress(const float p); + + /** + * Set's label above progress + */ + void setLabel(const std::string &); + + /** + * Enables play button + */ + void enable(); + + /** + * Loads and display news. Assumes the news file contents have been loaded + * into the memory buffer. + */ + void loadNews(); + + void loadPatch(); + + void action(const gcn::ActionEvent &event) override; + + void keyPressed(gcn::KeyEvent &keyEvent) override; + + void logic() override; + + void handleLink(const std::string &link, + gcn::MouseEvent *event A_UNUSED) override; + + static void loadLocalUpdates(const std::string &dir); + + static void unloadUpdates(const std::string &dir); + + static void addUpdateFile(const ResourceManager *const resman, + const std::string &path, + const std::string &fixPath, + const std::string &file, + const bool append); + + static void removeUpdateFile(const ResourceManager *const resman, + const std::string &path, + const std::string &fixPath, + const std::string &file); + + static void loadManaPlusUpdates(const std::string &dir, + const ResourceManager *const resman); + + static void unloadManaPlusUpdates(const std::string &dir, + const ResourceManager *const resman); + + static unsigned long getFileHash(const std::string &filePath); + +private: + void download(); + + /** + * Loads the updates this window has gotten into the resource manager + */ + void loadUpdates(); + + + /** + * A download callback for progress updates. + */ + static int updateProgress(void *ptr, DownloadStatus status, + size_t dt, size_t dn); + + /** + * A libcurl callback for writing to memory. + */ + static size_t memoryWrite(void *ptr, size_t size, size_t nmemb, + void *stream); + + static bool validateFile(const std::string &filePath, + const unsigned long hash) A_WARN_UNUSED; + + enum UpdateDownloadStatus + { + UPDATE_ERROR = 0, + UPDATE_IDLE, + UPDATE_LIST, + UPDATE_COMPLETE, + UPDATE_NEWS, + UPDATE_RESOURCES, + UPDATE_PATCH, + UPDATE_LIST2, + UPDATE_RESOURCES2 + }; + + /** Status of the current download. */ + UpdateDownloadStatus mDownloadStatus; + + /** Host where we get the updated files. */ + std::string mUpdateHost; + + /** Place where the updates are stored (absolute path). */ + std::string mUpdatesDir; + + std::string mUpdatesDirReal; + + /** The file currently downloading. */ + std::string mCurrentFile; + + /** The new label caption to be set in the logic method. */ + std::string mNewLabelCaption; + + /** The new progress value to be set in the logic method. */ + float mDownloadProgress; + + // The mutex used to guard access to mNewLabelCaption + // and mDownloadProgress. + Mutex mDownloadMutex; + + /** The Adler32 checksum of the file currently downloading. */ + unsigned long mCurrentChecksum; + + /** A flag to indicate whether to use a memory buffer or a regular file. */ + bool mStoreInMemory; + + /** Flag that show if current download is complete. */ + bool mDownloadComplete; + + /** Flag that show if the user has canceled the update. */ + bool mUserCancel; + + /** Byte count currently downloaded in mMemoryBuffer. */ + int mDownloadedBytes; + + /** Buffer for files downloaded to memory. */ + char *mMemoryBuffer; + + /** Download handle. */ + Net::Download *mDownload; + + /** List of files to download. */ + std::vector mUpdateFiles; + + /** List of temp files to download. */ + std::vector mTempUpdateFiles; + + /** Index of the file to be downloaded. */ + unsigned int mUpdateIndex; + + /** Index offset for disaplay downloaded file. */ + unsigned int mUpdateIndexOffset; + + /** Tells ~UpdaterWindow() if it should load updates */ + bool mLoadUpdates; + + int mUpdateType; + + Label *mLabel; /**< Progress bar caption. */ + Button *mCancelButton; /**< Button to stop the update process. */ + Button *mPlayButton; /**< Button to start playing. */ + ProgressBar *mProgressBar; /**< Update progress bar. */ + BrowserBox *mBrowserBox; /**< Box to display news. */ + ScrollArea *mScrollArea; /**< Used to scroll news box. */ + std::string mUpdateServerPath; +}; + +#endif // GUI_UPDATERWINDOW_H diff --git a/src/gui/windows/whoisonline.cpp b/src/gui/windows/whoisonline.cpp new file mode 100644 index 000000000..dafbb0419 --- /dev/null +++ b/src/gui/windows/whoisonline.cpp @@ -0,0 +1,866 @@ +/* + * The ManaPlus Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 Andrei Karas + * Copyright (C) 2011-2013 The ManaPlus developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/whoisonline.h" + +#include "guild.h" +#include "party.h" + +#include "gui/viewport.h" + +#include "gui/windows/chatwindow.h" +#include "gui/windows/socialwindow.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/browserbox.h" +#include "gui/widgets/scrollarea.h" + +#include "actorspritemanager.h" +#include "client.h" +#include "configuration.h" +#include "main.h" + +#include "being/localplayer.h" +#include "being/playerrelations.h" + +#include "net/download.h" +#include "net/net.h" +#include "net/playerhandler.h" + +#include "utils/gettext.h" +#include "utils/sdlhelper.h" + +#include +#include +#include + +// Curl should be included after Guichan to avoid Windows redefinitions +#include + +#include "debug.h" + +#ifdef free +#undef free +#endif + +#ifdef malloc +#undef malloc +#endif + +class NameFunctuator final +{ + public: + bool operator()(const OnlinePlayer *left, + const OnlinePlayer *right) const + { + return (compareStrI(left->getNick(), right->getNick()) < 0); + } +} nameCompare; + +WhoIsOnline::WhoIsOnline() : + // TRANSLATORS: who is online window name + Window(_("Who Is Online - Updating"), false, nullptr, "whoisonline.xml"), + mThread(nullptr), + mDownloadStatus(UPDATE_LIST), + mDownloadComplete(true), + mDownloadedBytes(0), + mMemoryBuffer(nullptr), + mCurlError(new char[CURL_ERROR_SIZE]), + mBrowserBox(new BrowserBox(this)), + mScrollArea(new ScrollArea(mBrowserBox, false)), + mUpdateTimer(0), + mOnlinePlayers(), + mOnlineNicks(), + // TRANSLATORS: who is online. button. + mUpdateButton(new Button(this, _("Update"), "update", this)), + mAllowUpdate(true), + mShowLevel(false), + mUpdateOnlineList(config.getBoolValue("updateOnlineList")), + + mGroupFriends(true) +{ + mCurlError[0] = 0; + setWindowName("WhoIsOnline"); + + const int h = 350; + const int w = 200; + setDefaultSize(w, h, ImageRect::CENTER); + setVisible(false); + setCloseButton(true); + setResizable(true); + setStickyButtonLock(true); + setSaveVisible(true); + + mUpdateButton->setEnabled(false); + mUpdateButton->setDimension(gcn::Rectangle(5, 5, w - 10, 20 + 5)); + + mBrowserBox->setOpaque(false); + mBrowserBox->setHighlightMode(BrowserBox::BACKGROUND); + mScrollArea->setDimension(gcn::Rectangle(5, 20 + 10, w - 10, h - 10 - 30)); + mScrollArea->setSize(w - 10, h - 10 - 30); + mBrowserBox->setLinkHandler(this); + + add(mUpdateButton); + add(mScrollArea); + + setLocationRelativeTo(getParent()); + + loadWindowState(); + enableVisibleSound(true); + + download(); + + widgetResized(gcn::Event(nullptr)); + config.addListener("updateOnlineList", this); + config.addListener("groupFriends", this); + mGroupFriends = config.getBoolValue("groupFriends"); +} + +WhoIsOnline::~WhoIsOnline() +{ + config.removeListeners(this); + + if (mThread && SDL_GetThreadID(mThread)) + SDL_WaitThread(mThread, nullptr); + + free(mMemoryBuffer); + mMemoryBuffer = nullptr; + + // Remove possibly leftover temporary download + delete []mCurlError; + + FOR_EACH (std::set::iterator, itd, mOnlinePlayers) + delete *itd; + mOnlinePlayers.clear(); + mOnlineNicks.clear(); +} + +void WhoIsOnline::handleLink(const std::string& link, gcn::MouseEvent *event) +{ + if (!event || event->getButton() == gcn::MouseEvent::LEFT) + { + if (chatWindow) + { + const std::string text = decodeLinkText(link); + if (config.getBoolValue("whispertab")) + { + chatWindow->localChatInput("/q " + text); + } + else + { + chatWindow->addInputText(std::string("/w \"").append( + text).append("\" ")); + } + } + } + else if (event->getButton() == gcn::MouseEvent::RIGHT) + { + if (player_node && link == player_node->getName()) + return; + + if (viewport) + { + if (actorSpriteManager) + { + const std::string text = decodeLinkText(link); + Being *const being = actorSpriteManager->findBeingByName( + text, Being::PLAYER); + + if (being && viewport) + { + viewport->showPopup(being); + return; + } + } + viewport->showPlayerPopup(link); + } + } +} + +void WhoIsOnline::updateWindow(std::vector &friends, + std::vector &neutral, + std::vector &disregard, + std::vector enemy, + size_t numOnline) +{ + // Set window caption + // TRANSLATORS: who is online window name + setCaption(_("Who Is Online - ") + toString(numOnline)); + + // List the online people + std::sort(friends.begin(), friends.end(), nameCompare); + std::sort(neutral.begin(), neutral.end(), nameCompare); + std::sort(disregard.begin(), disregard.end(), nameCompare); + bool addedFromSection(false); + FOR_EACH (std::vector::const_iterator, it, friends) + { + mBrowserBox->addRow((*it)->getText()); + addedFromSection = true; + } + if (addedFromSection == true) + { + mBrowserBox->addRow("---"); + addedFromSection = false; + } + FOR_EACH (std::vector::const_iterator, it, enemy) + { + mBrowserBox->addRow((*it)->getText()); + addedFromSection = true; + } + if (addedFromSection == true) + { + mBrowserBox->addRow("---"); + addedFromSection = false; + } + FOR_EACH (std::vector::const_iterator, it, neutral) + { + mBrowserBox->addRow((*it)->getText()); + addedFromSection = true; + } + if (addedFromSection == true && !disregard.empty()) + mBrowserBox->addRow("---"); + + FOR_EACH (std::vector::const_iterator, it, disregard) + mBrowserBox->addRow((*it)->getText()); + + if (mScrollArea->getVerticalMaxScroll() < + mScrollArea->getVerticalScrollAmount()) + { + mScrollArea->setVerticalScrollAmount( + mScrollArea->getVerticalMaxScroll()); + } +} + +void WhoIsOnline::loadList(std::vector &list) +{ + mBrowserBox->clearRows(); + const size_t numOnline = list.size(); + std::vector friends; + std::vector neutral; + std::vector disregard; + std::vector enemy; + + FOR_EACH (std::set::iterator, itd, mOnlinePlayers) + delete *itd; + mOnlinePlayers.clear(); + mOnlineNicks.clear(); + + mShowLevel = config.getBoolValue("showlevel"); + + FOR_EACH (std::vector::const_iterator, it, list) + { + OnlinePlayer *player = *it; + const std::string nick = player->getNick(); + mOnlinePlayers.insert(player); + mOnlineNicks.insert(nick); + + if (!mShowLevel) + player->setLevel(0); + + switch (player_relations.getRelation(nick)) + { + case PlayerRelation::NEUTRAL: + default: + setNeutralColor(player); + neutral.push_back(player); + break; + + case PlayerRelation::FRIEND: + player->setText("2"); + if (mGroupFriends) + friends.push_back(player); + else + neutral.push_back(player); + break; + + case PlayerRelation::DISREGARDED: + case PlayerRelation::BLACKLISTED: + player->setText("8"); + disregard.push_back(player); + break; + + case PlayerRelation::ENEMY2: + player->setText("1"); + enemy.push_back(player); + break; + + case PlayerRelation::IGNORED: + case PlayerRelation::ERASED: + // Ignore the ignored. + break; + } + } + + updateWindow(friends, neutral, disregard, enemy, numOnline); + if (!mOnlineNicks.empty()) + { + if (chatWindow) + chatWindow->updateOnline(mOnlineNicks); + if (socialWindow) + socialWindow->updateActiveList(); + } + updateSize(); +} + +void WhoIsOnline::loadWebList() +{ + if (!mMemoryBuffer) + return; + + // Reallocate and include terminating 0 character + mMemoryBuffer = static_cast( + realloc(mMemoryBuffer, mDownloadedBytes + 1)); + mMemoryBuffer[mDownloadedBytes] = '\0'; + + mBrowserBox->clearRows(); + bool listStarted(false); + std::string lineStr; + int numOnline(0); + std::vector friends; + std::vector neutral; + std::vector disregard; + std::vector enemy; + + // Tokenize and add each line separately + char *line = strtok(mMemoryBuffer, "\n"); + const std::string gmText("(GM)"); + + FOR_EACH (std::set::iterator, itd, mOnlinePlayers) + delete *itd; + + mOnlinePlayers.clear(); + mOnlineNicks.clear(); + + mShowLevel = config.getBoolValue("showlevel"); + + while (line) + { + std::string nick; + lineStr = line; + trim(lineStr); + if (listStarted == true) + { + if (lineStr.find(" users are online.") == std::string::npos) + { + if (lineStr.length() > 24) + { + nick = lineStr.substr(0, 24); + lineStr = lineStr.substr(25); + } + else + { + nick = lineStr; + lineStr.clear(); + } + trim(nick); + + bool isGM(false); + size_t pos = lineStr.find(gmText, 0); + if (pos != std::string::npos) + { + lineStr = lineStr.substr(pos + gmText.length()); + isGM = true; + } + + trim(lineStr); + pos = lineStr.find("/", 0); + + if (pos != std::string::npos) + lineStr = lineStr.substr(0, pos); + + int level = 0; + if (!lineStr.empty()) + level = atoi(lineStr.c_str()); + + if (actorSpriteManager) + { + Being *const being = actorSpriteManager->findBeingByName( + nick, Being::PLAYER); + if (being) + { + if (level > 0) + { + being->setLevel(level); + being->updateName(); + } + else + { + if (being->getLevel() > 1) + level = being->getLevel(); + } + } + } + + if (!mShowLevel) + level = 0; + + OnlinePlayer *const player = new OnlinePlayer(nick, + static_cast(255), level, + GENDER_UNSPECIFIED, -1); + mOnlinePlayers.insert(player); + mOnlineNicks.insert(nick); + + if (isGM) + player->setIsGM(true); + + numOnline++; + switch (player_relations.getRelation(nick)) + { + case PlayerRelation::NEUTRAL: + default: + setNeutralColor(player); + neutral.push_back(player); + break; + + case PlayerRelation::FRIEND: + player->setText("2"); + if (mGroupFriends) + friends.push_back(player); + else + neutral.push_back(player); + break; + + case PlayerRelation::DISREGARDED: + case PlayerRelation::BLACKLISTED: + player->setText("8"); + disregard.push_back(player); + break; + + case PlayerRelation::ENEMY2: + player->setText("1"); + enemy.push_back(player); + break; + + case PlayerRelation::IGNORED: + case PlayerRelation::ERASED: + // Ignore the ignored. + break; + } + } + } + else if (lineStr.find("------------------------------") + != std::string::npos) + { + listStarted = true; + } + line = strtok(nullptr, "\n"); + } + + updateWindow(friends, neutral, disregard, enemy, numOnline); + + // Free the memory buffer now that we don't need it anymore + free(mMemoryBuffer); + mMemoryBuffer = nullptr; +} + +size_t WhoIsOnline::memoryWrite(void *ptr, size_t size, + size_t nmemb, FILE *stream) +{ + if (!stream) + return 0; + + WhoIsOnline *const wio = reinterpret_cast(stream); + const size_t totalMem = size * nmemb; + wio->mMemoryBuffer = static_cast(realloc(wio->mMemoryBuffer, + wio->mDownloadedBytes + totalMem)); + if (wio->mMemoryBuffer) + { + memcpy(&(wio->mMemoryBuffer[wio->mDownloadedBytes]), ptr, totalMem); + wio->mDownloadedBytes += static_cast(totalMem); + } + + return totalMem; +} + +int WhoIsOnline::downloadThread(void *ptr) +{ + int attempts = 0; + WhoIsOnline *const wio = reinterpret_cast(ptr); + CURLcode res; + const std::string url(client->getOnlineUrl() + "/online.txt"); + + while (attempts < 1 && !wio->mDownloadComplete) + { + CURL *curl = curl_easy_init(); + if (curl) + { + if (!wio->mAllowUpdate) + { + curl_easy_cleanup(curl); + curl = nullptr; + break; + } + wio->mDownloadedBytes = 0; + curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, + WhoIsOnline::memoryWrite); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, ptr); + + curl_easy_setopt(curl, CURLOPT_USERAGENT, + strprintf(PACKAGE_EXTENDED_VERSION, + branding.getStringValue("appName").c_str()).c_str()); + + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, wio->mCurlError); + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, ptr); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 7); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30); + Net::Download::addProxy(curl); + Net::Download::secureCurl(curl); + + // Make sure the resources2.txt and news.txt aren't cached, + // in order to always get the latest version. + struct curl_slist *pHeaders = nullptr; + pHeaders = curl_slist_append( + pHeaders, "pragma: no-cache"); + pHeaders = curl_slist_append(pHeaders, + "Cache-Control: no-cache"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, pHeaders); + + if ((res = curl_easy_perform(curl)) != 0) + { + wio->mDownloadStatus = UPDATE_ERROR; + switch (res) + { + case CURLE_COULDNT_CONNECT: + default: + std::cerr << "curl error " + << static_cast(res) << ": " + << wio->mCurlError << " host: " + << url.c_str() << std::endl; + break; + } + attempts++; + curl_easy_cleanup(curl); + curl_slist_free_all(pHeaders); + curl = nullptr; + continue; + } + + curl_easy_cleanup(curl); + curl_slist_free_all(pHeaders); + + // It's stored in memory, we're done + wio->mDownloadComplete = true; + } + if (!wio->mAllowUpdate) + break; + attempts++; + } + + if (!wio->mDownloadComplete) + wio->mDownloadStatus = UPDATE_ERROR; + return 0; +} + +void WhoIsOnline::download() +{ + if (serverVersion < 3) + { + mDownloadComplete = true; + if (mThread && SDL_GetThreadID(mThread)) + SDL_WaitThread(mThread, nullptr); + + mDownloadComplete = false; + mThread = SDL::createThread(WhoIsOnline::downloadThread, + "whoisonline", this); + if (mThread == nullptr) + mDownloadStatus = UPDATE_ERROR; + } + else + { + if (client->limitPackets(PACKET_ONLINELIST)) + Net::getPlayerHandler()->requestOnlineList(); + } +} + +void WhoIsOnline::logic() +{ + BLOCK_START("WhoIsOnline::logic") + mScrollArea->logic(); + BLOCK_END("WhoIsOnline::logic") +} + +void WhoIsOnline::slowLogic() +{ + if (!mAllowUpdate) + return; + + BLOCK_START("WhoIsOnline::slowLogic") + if (mUpdateTimer == 0) + mUpdateTimer = cur_time; + + const double timeDiff = difftime(cur_time, mUpdateTimer); + const int timeLimit = isWindowVisible() ? 20 : 120; + + if (mUpdateOnlineList && timeDiff >= timeLimit + && mDownloadStatus != UPDATE_LIST) + { + if (mDownloadComplete == true) + { + // TRANSLATORS: who is online window name + setCaption(_("Who Is Online - Updating")); + mUpdateTimer = 0; + mDownloadStatus = UPDATE_LIST; + download(); + } + } + + switch (mDownloadStatus) + { + case UPDATE_ERROR: + mBrowserBox->clearRows(); + mBrowserBox->addRow("##1Failed to fetch the online list!"); + mBrowserBox->addRow(mCurlError); + mDownloadStatus = UPDATE_COMPLETE; + // TRANSLATORS: who is online window name + setCaption(_("Who Is Online - error")); + mUpdateButton->setEnabled(true); + mUpdateTimer = cur_time + 240; + mDownloadComplete = true; + updateSize(); + break; + case UPDATE_LIST: + if (mDownloadComplete == true) + { + loadWebList(); + mDownloadStatus = UPDATE_COMPLETE; + mUpdateButton->setEnabled(true); + mUpdateTimer = 0; + updateSize(); + if (!mOnlineNicks.empty()) + { + if (chatWindow) + chatWindow->updateOnline(mOnlineNicks); + if (socialWindow) + socialWindow->updateActiveList(); + } + } + break; + case UPDATE_COMPLETE: + default: + break; + } + BLOCK_END("WhoIsOnline::slowLogic") +} + +void WhoIsOnline::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "update") + { + if (serverVersion < 3) + { + if (mDownloadStatus == UPDATE_COMPLETE) + { + mUpdateTimer = cur_time - 20; + if (mUpdateButton) + mUpdateButton->setEnabled(false); + // TRANSLATORS: who is online window name + setCaption(_("Who Is Online - Update")); + if (mThread && SDL_GetThreadID(mThread)) + { + SDL_WaitThread(mThread, nullptr); + mThread = nullptr; + } + mDownloadComplete = true; + } + } + else + { + if (client->limitPackets(PACKET_ONLINELIST)) + { + mUpdateTimer = cur_time; + Net::getPlayerHandler()->requestOnlineList(); + } + } + } +} + +void WhoIsOnline::widgetResized(const gcn::Event &event) +{ + Window::widgetResized(event); + updateSize(); +} + +void WhoIsOnline::updateSize() +{ + const gcn::Rectangle area = getChildrenArea(); + if (mUpdateButton) + mUpdateButton->setWidth(area.width - 10); + + if (mScrollArea) + mScrollArea->setSize(area.width - 10, area.height - 10 - 30); + if (mBrowserBox) + mBrowserBox->setWidth(area.width - 10); +} + +const std::string WhoIsOnline::prepareNick(const std::string &nick, + const int level, + const std::string &color) const +{ + const std::string text = encodeLinkText(nick); + if (mShowLevel && level > 1) + { + return strprintf("@@%s|##%s%s (%d)@@", text.c_str(), + color.c_str(), text.c_str(), level); + } + else + { + return strprintf("@@%s|##%s%s@@", text.c_str(), + color.c_str(), text.c_str()); + } +} + +void WhoIsOnline::optionChanged(const std::string &name) +{ + if (name == "updateOnlineList") + mUpdateOnlineList = config.getBoolValue("updateOnlineList"); + else if (name == "groupFriends") + mGroupFriends = config.getBoolValue("groupFriends"); +} + +void WhoIsOnline::setNeutralColor(OnlinePlayer *const player) +{ + if (!player) + return; + + if (actorSpriteManager && player_node) + { + const std::string &nick = player->getNick(); + if (nick == player_node->getName()) + { + player->setText("s"); + return; + } + if (player_node->isInParty()) + { + const Party *const party = player_node->getParty(); + if (party) + { + if (party->getMember(nick)) + { + player->setText("P"); + return; + } + } + } + + const Being *const being = actorSpriteManager->findBeingByName(nick); + if (being) + { + const Guild *const guild2 = player_node->getGuild(); + if (guild2) + { + const Guild *const guild1 = being->getGuild(); + if (guild1) + { + if (guild1->getId() == guild2->getId() + || guild2->getMember(nick)) + { + player->setText("U"); + return; + } + } + else if (guild2->isMember(nick)) + { + player->setText("U"); + return; + } + } + } + const Guild *const guild3 = Guild::getGuild(1); + if (guild3 && guild3->isMember(nick)) + { + player->setText("U"); + return; + } + } + player->setText("0"); +} + +void WhoIsOnline::getPlayerNames(StringVect &names) +{ + names.clear(); + FOR_EACH (std::set::const_iterator, it, mOnlineNicks) + names.push_back(*it); +} + +void OnlinePlayer::setText(std::string color) +{ + mText.clear(); + + if (mStatus != 255 && actorSpriteManager) + { + Being *const being = actorSpriteManager->findBeingByName( + mNick, Being::PLAYER); + if (being) + { + being->setState(mStatus); + // for now highlight versions > 3 + if (mVersion > 3) + being->setAdvanced(true); + } + } + + if ((mStatus != 255 && mStatus & Being::FLAG_GM) || mIsGM) + mText.append("(GM) "); + + if (mLevel > 0) + mText.append(strprintf("%d", mLevel)); + + if (mGender == GENDER_FEMALE) + mText.append("\u2640"); + else if (mGender == GENDER_MALE) + mText.append("\u2642"); + + if (mStatus > 0 && mStatus != 255) + { + if (mStatus & Being::FLAG_SHOP) + mText.append("$"); + if (mStatus & Being::FLAG_AWAY) + { + // TRANSLATORS: this away status writed in player nick + mText.append(_("A")); + } + if (mStatus & Being::FLAG_INACTIVE) + { + // TRANSLATORS: this inactive status writed in player nick + mText.append(_("I")); + } + + if (mStatus & Being::FLAG_GM && color == "0") + color = "2"; + } + else if (mIsGM && color == "0") + { + color = "2"; + } + + if (mVersion > 0) + mText.append(strprintf(" - %d", mVersion)); + + const std::string text = encodeLinkText(mNick); + mText = strprintf("@@%s|##%s%s %s@@", text.c_str(), color.c_str(), + text.c_str(), mText.c_str()); +} diff --git a/src/gui/windows/whoisonline.h b/src/gui/windows/whoisonline.h new file mode 100644 index 000000000..860eeacda --- /dev/null +++ b/src/gui/windows/whoisonline.h @@ -0,0 +1,223 @@ +/* + * The ManaPlus Client + * Copyright (C) 2009 The Mana World Development Team + * Copyright (C) 2009-2010 Andrei Karas + * Copyright (C) 2011-2013 The ManaPlus developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_WHOISONLINE_H +#define GUI_WHOISONLINE_H + +#include "configlistener.h" + +#include "gui/widgets/linkhandler.h" +#include "gui/widgets/window.h" + +#include + +#include + +class BrowserBox; +class Button; +class ScrollArea; + +struct SDL_Thread; + +class OnlinePlayer final +{ + public: + OnlinePlayer(const std::string &nick, const unsigned char status, + const char level, const unsigned char gender, + const char version) : + mNick(nick), + mText(""), + mStatus(status), + mLevel(level), + mVersion(version), + mGender(gender), + mIsGM(false) + { + } + + A_DELETE_COPY(OnlinePlayer) + + const std::string getNick() const A_WARN_UNUSED + { return mNick; } + + unsigned char getStaus() const A_WARN_UNUSED + { return mStatus; } + + void setIsGM(const bool b) + { mIsGM = b; } + + char getVersion() const A_WARN_UNUSED + { return mVersion; } + + char getLevel() const A_WARN_UNUSED + { return mLevel; } + + const std::string getText() const A_WARN_UNUSED + { return mText; } + + void setText(std::string str); + + void setLevel(const char level) + { mLevel = level; } + + private: + std::string mNick; + + std::string mText; + + unsigned char mStatus; + + char mLevel; + + char mVersion; + + unsigned char mGender; + + bool mIsGM; +}; + +/** + * Update progress window GUI + * + * \ingroup GUI + */ +class WhoIsOnline final : public Window, + public LinkHandler, + public gcn::ActionListener, + public ConfigListener +{ +public: + /** + * Constructor. + */ + WhoIsOnline(); + + A_DELETE_COPY(WhoIsOnline) + + /** + * Destructor + */ + ~WhoIsOnline(); + + /** + * Loads and display online list from the memory buffer. + */ + void loadWebList(); + + void loadList(std::vector &list); + + void handleLink(const std::string& link, gcn::MouseEvent *event) override; + + void logic() override; + + void slowLogic(); + + void action(const gcn::ActionEvent &event) override; + + void widgetResized(const gcn::Event &event) override; + + const std::set &getOnlinePlayers() const A_WARN_UNUSED + { return mOnlinePlayers; } + + const std::set &getOnlineNicks() const A_WARN_UNUSED + { return mOnlineNicks; } + + void setAllowUpdate(const bool n) + { mAllowUpdate = n; } + + void optionChanged(const std::string &name) override; + + void updateList(StringVect &list); + + void readFromWeb(); + + void setNeutralColor(OnlinePlayer *const player); + + void getPlayerNames(StringVect &names); + +private: + void download(); + + void updateSize(); + + /** + * The thread function that download the files. + */ + static int downloadThread(void *ptr); + + /** + * A libcurl callback for writing to memory. + */ + static size_t memoryWrite(void *ptr, size_t size, size_t nmemb, + FILE *stream); + + const std::string prepareNick(const std::string &nick, const int level, + const std::string &color) + const A_WARN_UNUSED; + + void updateWindow(std::vector &friends, + std::vector &neutral, + std::vector &disregard, + std::vector enemy, + size_t numOnline); + + enum DownloadStatus + { + UPDATE_ERROR = 0, + UPDATE_COMPLETE, + UPDATE_LIST + }; + + /** A thread that use libcurl to download updates. */ + SDL_Thread *mThread; + + /** Status of the current download. */ + DownloadStatus mDownloadStatus; + + /** Flag that show if current download is complete. */ + bool mDownloadComplete; + + /** Byte count currently downloaded in mMemoryBuffer. */ + int mDownloadedBytes; + + /** Buffer for files downloaded to memory. */ + char *mMemoryBuffer; + + /** Buffer to handler human readable error provided by curl. */ + char *mCurlError; + + BrowserBox *mBrowserBox; + ScrollArea *mScrollArea; + time_t mUpdateTimer; + std::set mOnlinePlayers; + std::set mOnlineNicks; + + Button *mUpdateButton; + bool mAllowUpdate; + bool mShowLevel; + bool mUpdateOnlineList; + bool mGroupFriends; +}; + +extern WhoIsOnline *whoIsOnline; + +#endif // GUI_WHOISONLINE_H diff --git a/src/gui/windows/worldselectdialog.cpp b/src/gui/windows/worldselectdialog.cpp new file mode 100644 index 000000000..bd46df9a1 --- /dev/null +++ b/src/gui/windows/worldselectdialog.cpp @@ -0,0 +1,166 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui/windows/worldselectdialog.h" + +#include "client.h" + +#include "input/keydata.h" +#include "input/keyevent.h" + +#include "gui/widgets/button.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/listbox.h" +#include "gui/widgets/scrollarea.h" + +#include "net/loginhandler.h" +#include "net/net.h" + +#include "utils/gettext.h" + +#include "debug.h" + +extern WorldInfo **server_info; + +/** + * The list model for the server list. + */ +class WorldListModel final : public gcn::ListModel +{ + public: + explicit WorldListModel(Worlds worlds) : + mWorlds(worlds) + { + } + + A_DELETE_COPY(WorldListModel) + + ~WorldListModel() + { } + + int getNumberOfElements() override + { + return static_cast(mWorlds.size()); + } + + std::string getElementAt(int i) override + { + const WorldInfo *const si = mWorlds[i]; + if (si) + { + return std::string(si->name).append(" (").append( + toString(si->online_users)).append(")"); + } + else + { + return "???"; + } + } + private: + Worlds mWorlds; +}; + +WorldSelectDialog::WorldSelectDialog(Worlds worlds): + // TRANSLATORS: world select dialog name + Window(_("Select World"), false, nullptr, "world.xml"), + gcn::ActionListener(), + gcn::KeyListener(), + mWorldListModel(new WorldListModel(worlds)), + mWorldList(new ListBox(this, mWorldListModel, "")), + // TRANSLATORS: world dialog button + mChangeLoginButton(new Button(this, _("Change Login"), "login", this)), + // TRANSLATORS: world dialog button + mChooseWorld(new Button(this, _("Choose World"), "world", this)) +{ + ScrollArea *const worldsScroll = new ScrollArea(mWorldList, + getOptionBool("showbackground"), "world_background.xml"); + + worldsScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + + place(0, 0, worldsScroll, 3, 5).setPadding(2); + place(1, 5, mChangeLoginButton); + place(2, 5, mChooseWorld); + + // Make sure the list has enough height + getLayout().setRowHeight(0, 60); + + reflowLayout(0, 0); + + if (worlds.empty()) + { + // Disable Ok button + mChooseWorld->setEnabled(false); + } + else + { + // Select first server + mWorldList->setSelected(0); + } + + addKeyListener(this); + + center(); + setVisible(true); + mChooseWorld->requestFocus(); +} + +WorldSelectDialog::~WorldSelectDialog() +{ + delete mWorldListModel; + mWorldListModel = nullptr; +} + +void WorldSelectDialog::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "world") + { + mChangeLoginButton->setEnabled(false); + mChooseWorld->setEnabled(false); + Net::getLoginHandler()->chooseServer(mWorldList->getSelected()); + + // Check in case netcode moves us forward + if (client->getState() == STATE_WORLD_SELECT) + client->setState(STATE_WORLD_SELECT_ATTEMPT); + } + else if (eventId == "login") + { + client->setState(STATE_PRE_LOGIN); + } +} + +void WorldSelectDialog::keyPressed(gcn::KeyEvent &keyEvent) +{ + const int actionId = static_cast( + &keyEvent)->getActionId(); + + if (actionId == static_cast(Input::KEY_GUI_CANCEL)) + { + action(gcn::ActionEvent(nullptr, + mChangeLoginButton->getActionEventId())); + } + else if (actionId == static_cast(Input::KEY_GUI_SELECT) + || actionId == static_cast(Input::KEY_GUI_SELECT2)) + { + action(gcn::ActionEvent(nullptr, mChooseWorld->getActionEventId())); + } +} diff --git a/src/gui/windows/worldselectdialog.h b/src/gui/windows/worldselectdialog.h new file mode 100644 index 000000000..ace7fd63c --- /dev/null +++ b/src/gui/windows/worldselectdialog.h @@ -0,0 +1,74 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GUI_WORLDSELECTDIALOG_H +#define GUI_WORLDSELECTDIALOG_H + +#include "gui/widgets/window.h" + +#include "net/worldinfo.h" + +#include +#include + +class Button; +class ListBox; +class WorldListModel; + +/** + * The server select dialog. + * + * \ingroup Interface + */ +class WorldSelectDialog final : public Window, public gcn::ActionListener, + public gcn::KeyListener +{ + public: + /** + * Constructor + * + * @see Window::Window + */ + explicit WorldSelectDialog(Worlds worlds); + + A_DELETE_COPY(WorldSelectDialog) + + /** + * Destructor. + */ + ~WorldSelectDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event) override; + + void keyPressed(gcn::KeyEvent &keyEvent) override; + + private: + WorldListModel *mWorldListModel; + ListBox *mWorldList; + Button *mChangeLoginButton; + Button *mChooseWorld; +}; + +#endif // GUI_WORLDSELECTDIALOG_H diff --git a/src/gui/worldselectdialog.cpp b/src/gui/worldselectdialog.cpp deleted file mode 100644 index d65c02e4f..000000000 --- a/src/gui/worldselectdialog.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "gui/worldselectdialog.h" - -#include "client.h" - -#include "input/keydata.h" -#include "input/keyevent.h" - -#include "gui/widgets/button.h" -#include "gui/widgets/layout.h" -#include "gui/widgets/listbox.h" -#include "gui/widgets/scrollarea.h" - -#include "net/loginhandler.h" -#include "net/net.h" - -#include "utils/gettext.h" - -#include "debug.h" - -extern WorldInfo **server_info; - -/** - * The list model for the server list. - */ -class WorldListModel final : public gcn::ListModel -{ - public: - explicit WorldListModel(Worlds worlds) : - mWorlds(worlds) - { - } - - A_DELETE_COPY(WorldListModel) - - ~WorldListModel() - { } - - int getNumberOfElements() override - { - return static_cast(mWorlds.size()); - } - - std::string getElementAt(int i) override - { - const WorldInfo *const si = mWorlds[i]; - if (si) - { - return std::string(si->name).append(" (").append( - toString(si->online_users)).append(")"); - } - else - { - return "???"; - } - } - private: - Worlds mWorlds; -}; - -WorldSelectDialog::WorldSelectDialog(Worlds worlds): - // TRANSLATORS: world select dialog name - Window(_("Select World"), false, nullptr, "world.xml"), - gcn::ActionListener(), - gcn::KeyListener(), - mWorldListModel(new WorldListModel(worlds)), - mWorldList(new ListBox(this, mWorldListModel, "")), - // TRANSLATORS: world dialog button - mChangeLoginButton(new Button(this, _("Change Login"), "login", this)), - // TRANSLATORS: world dialog button - mChooseWorld(new Button(this, _("Choose World"), "world", this)) -{ - ScrollArea *const worldsScroll = new ScrollArea(mWorldList, - getOptionBool("showbackground"), "world_background.xml"); - - worldsScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - - place(0, 0, worldsScroll, 3, 5).setPadding(2); - place(1, 5, mChangeLoginButton); - place(2, 5, mChooseWorld); - - // Make sure the list has enough height - getLayout().setRowHeight(0, 60); - - reflowLayout(0, 0); - - if (worlds.empty()) - { - // Disable Ok button - mChooseWorld->setEnabled(false); - } - else - { - // Select first server - mWorldList->setSelected(0); - } - - addKeyListener(this); - - center(); - setVisible(true); - mChooseWorld->requestFocus(); -} - -WorldSelectDialog::~WorldSelectDialog() -{ - delete mWorldListModel; - mWorldListModel = nullptr; -} - -void WorldSelectDialog::action(const gcn::ActionEvent &event) -{ - const std::string &eventId = event.getId(); - if (eventId == "world") - { - mChangeLoginButton->setEnabled(false); - mChooseWorld->setEnabled(false); - Net::getLoginHandler()->chooseServer(mWorldList->getSelected()); - - // Check in case netcode moves us forward - if (client->getState() == STATE_WORLD_SELECT) - client->setState(STATE_WORLD_SELECT_ATTEMPT); - } - else if (eventId == "login") - { - client->setState(STATE_PRE_LOGIN); - } -} - -void WorldSelectDialog::keyPressed(gcn::KeyEvent &keyEvent) -{ - const int actionId = static_cast( - &keyEvent)->getActionId(); - - if (actionId == static_cast(Input::KEY_GUI_CANCEL)) - { - action(gcn::ActionEvent(nullptr, - mChangeLoginButton->getActionEventId())); - } - else if (actionId == static_cast(Input::KEY_GUI_SELECT) - || actionId == static_cast(Input::KEY_GUI_SELECT2)) - { - action(gcn::ActionEvent(nullptr, mChooseWorld->getActionEventId())); - } -} diff --git a/src/gui/worldselectdialog.h b/src/gui/worldselectdialog.h deleted file mode 100644 index ace7fd63c..000000000 --- a/src/gui/worldselectdialog.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2013 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GUI_WORLDSELECTDIALOG_H -#define GUI_WORLDSELECTDIALOG_H - -#include "gui/widgets/window.h" - -#include "net/worldinfo.h" - -#include -#include - -class Button; -class ListBox; -class WorldListModel; - -/** - * The server select dialog. - * - * \ingroup Interface - */ -class WorldSelectDialog final : public Window, public gcn::ActionListener, - public gcn::KeyListener -{ - public: - /** - * Constructor - * - * @see Window::Window - */ - explicit WorldSelectDialog(Worlds worlds); - - A_DELETE_COPY(WorldSelectDialog) - - /** - * Destructor. - */ - ~WorldSelectDialog(); - - /** - * Called when receiving actions from the widgets. - */ - void action(const gcn::ActionEvent &event) override; - - void keyPressed(gcn::KeyEvent &keyEvent) override; - - private: - WorldListModel *mWorldListModel; - ListBox *mWorldList; - Button *mChangeLoginButton; - Button *mChooseWorld; -}; - -#endif // GUI_WORLDSELECTDIALOG_H diff --git a/src/guildmanager.cpp b/src/guildmanager.cpp index bd6fe9f59..b4fff604e 100644 --- a/src/guildmanager.cpp +++ b/src/guildmanager.cpp @@ -29,7 +29,7 @@ #include "being/localplayer.h" -#include "gui/socialwindow.h" +#include "gui/windows/socialwindow.h" #include "gui/widgets/guildchattab.h" diff --git a/src/input/inputmanager.cpp b/src/input/inputmanager.cpp index d5e3b3957..04b4744b6 100644 --- a/src/input/inputmanager.cpp +++ b/src/input/inputmanager.cpp @@ -31,16 +31,18 @@ #include "input/keyboardconfig.h" #include "input/keyboarddata.h" -#include "gui/chatwindow.h" #include "gui/gui.h" -#include "gui/inventorywindow.h" -#include "gui/npcdialog.h" -#include "gui/npcpostdialog.h" #include "gui/sdlinput.h" -#include "gui/setup.h" #include "gui/setup_input.h" -#include "gui/textdialog.h" -#include "gui/tradewindow.h" + +#include "gui/windows/inventorywindow.h" +#include "gui/windows/npcdialog.h" +#include "gui/windows/npcpostdialog.h" +#include "gui/windows/setup.h" +#include "gui/windows/textdialog.h" +#include "gui/windows/tradewindow.h" + +#include "gui/windows/chatwindow.h" #include #include diff --git a/src/itemshortcut.cpp b/src/itemshortcut.cpp index 9332211ce..5ef762de8 100644 --- a/src/itemshortcut.cpp +++ b/src/itemshortcut.cpp @@ -30,7 +30,7 @@ #include "being/playerinfo.h" -#include "gui/skilldialog.h" +#include "gui/windows/skilldialog.h" #include "net/inventoryhandler.h" #include "net/net.h" diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp index 0e8add107..56ec0bf79 100644 --- a/src/net/charserverhandler.cpp +++ b/src/net/charserverhandler.cpp @@ -21,7 +21,7 @@ #include "net/charserverhandler.h" -#include "gui/charselectdialog.h" +#include "gui/windows/charselectdialog.h" #include "debug.h" diff --git a/src/net/ea/beinghandler.cpp b/src/net/ea/beinghandler.cpp index 7702a5a9b..956f4d20b 100644 --- a/src/net/ea/beinghandler.cpp +++ b/src/net/ea/beinghandler.cpp @@ -39,11 +39,13 @@ #include "input/keyboardconfig.h" -#include "gui/botcheckerwindow.h" -#include "gui/outfitwindow.h" -#include "gui/socialwindow.h" -#include "gui/killstats.h" -#include "gui/questswindow.h" +#include "gui/windows/socialwindow.h" +#include "gui/windows/killstats.h" +#include "gui/windows/questswindow.h" + +#include "gui/windows/botcheckerwindow.h" + +#include "gui/windows/outfitwindow.h" #include "resources/itemdb.h" #include "resources/iteminfo.h" diff --git a/src/net/ea/buysellhandler.cpp b/src/net/ea/buysellhandler.cpp index 601c3fbdf..15a4385dc 100644 --- a/src/net/ea/buysellhandler.cpp +++ b/src/net/ea/buysellhandler.cpp @@ -30,11 +30,12 @@ #include "being/playerinfo.h" -#include "gui/buydialog.h" -#include "gui/chatwindow.h" -#include "gui/buyselldialog.h" -#include "gui/selldialog.h" -#include "gui/shopwindow.h" +#include "gui/windows/chatwindow.h" +#include "gui/windows/buyselldialog.h" +#include "gui/windows/selldialog.h" + +#include "gui/windows/buydialog.h" +#include "gui/windows/shopwindow.h" #include "net/chathandler.h" #include "net/net.h" diff --git a/src/net/ea/charserverhandler.cpp b/src/net/ea/charserverhandler.cpp index 7ff7e6eb8..4caa6ac3b 100644 --- a/src/net/ea/charserverhandler.cpp +++ b/src/net/ea/charserverhandler.cpp @@ -25,8 +25,8 @@ #include "client.h" #include "configuration.h" -#include "gui/charcreatedialog.h" -#include "gui/okdialog.h" +#include "gui/windows/charcreatedialog.h" +#include "gui/windows/okdialog.h" #include "net/ea/loginhandler.h" #include "net/ea/eaprotocol.h" diff --git a/src/net/ea/chathandler.cpp b/src/net/ea/chathandler.cpp index 403848a88..873e93aee 100644 --- a/src/net/ea/chathandler.cpp +++ b/src/net/ea/chathandler.cpp @@ -31,8 +31,8 @@ #include "being/localplayer.h" #include "being/playerrelations.h" -#include "gui/chatwindow.h" -#include "gui/shopwindow.h" +#include "gui/windows/chatwindow.h" +#include "gui/windows/shopwindow.h" #include "gui/widgets/chattab.h" #include "gui/widgets/gmtab.h" diff --git a/src/net/ea/gamehandler.cpp b/src/net/ea/gamehandler.cpp index 0f0192dfa..54371d247 100644 --- a/src/net/ea/gamehandler.cpp +++ b/src/net/ea/gamehandler.cpp @@ -29,7 +29,7 @@ #include "being/localplayer.h" -#include "gui/okdialog.h" +#include "gui/windows/okdialog.h" #include "debug.h" diff --git a/src/net/ea/guildhandler.cpp b/src/net/ea/guildhandler.cpp index 47205f2f4..7e46438d2 100644 --- a/src/net/ea/guildhandler.cpp +++ b/src/net/ea/guildhandler.cpp @@ -28,7 +28,7 @@ #include "being/localplayer.h" -#include "gui/socialwindow.h" +#include "gui/windows/socialwindow.h" #include "debug.h" diff --git a/src/net/ea/inventoryhandler.cpp b/src/net/ea/inventoryhandler.cpp index 69e1d7587..68bbe85b0 100644 --- a/src/net/ea/inventoryhandler.cpp +++ b/src/net/ea/inventoryhandler.cpp @@ -27,7 +27,7 @@ #include "being/localplayer.h" -#include "gui/ministatuswindow.h" +#include "gui/windows/ministatuswindow.h" #include "net/ea/eaprotocol.h" diff --git a/src/net/ea/inventoryhandler.h b/src/net/ea/inventoryhandler.h index 776443cf7..9f55a3603 100644 --- a/src/net/ea/inventoryhandler.h +++ b/src/net/ea/inventoryhandler.h @@ -30,7 +30,7 @@ #include "being/playerinfo.h" -#include "gui/inventorywindow.h" +#include "gui/windows/inventorywindow.h" #include "net/inventoryhandler.h" #include "net/messagein.h" diff --git a/src/net/ea/loginhandler.cpp b/src/net/ea/loginhandler.cpp index 59d72dd78..d67f1d37a 100644 --- a/src/net/ea/loginhandler.cpp +++ b/src/net/ea/loginhandler.cpp @@ -26,7 +26,7 @@ #include "configuration.h" #include "logger.h" -#include "gui/logindialog.h" +#include "gui/windows/logindialog.h" #include "utils/dtor.h" #include "utils/gettext.h" diff --git a/src/net/ea/npchandler.cpp b/src/net/ea/npchandler.cpp index 654a783b3..b3af53e87 100644 --- a/src/net/ea/npchandler.cpp +++ b/src/net/ea/npchandler.cpp @@ -22,7 +22,7 @@ #include "net/ea/npchandler.h" -#include "gui/npcdialog.h" +#include "gui/windows/npcdialog.h" #include "debug.h" diff --git a/src/net/ea/partyhandler.cpp b/src/net/ea/partyhandler.cpp index b7353be26..6b2462450 100644 --- a/src/net/ea/partyhandler.cpp +++ b/src/net/ea/partyhandler.cpp @@ -28,7 +28,7 @@ #include "being/localplayer.h" -#include "gui/socialwindow.h" +#include "gui/windows/socialwindow.h" #include "debug.h" diff --git a/src/net/ea/playerhandler.cpp b/src/net/ea/playerhandler.cpp index 320727e01..03e62f45e 100644 --- a/src/net/ea/playerhandler.cpp +++ b/src/net/ea/playerhandler.cpp @@ -31,13 +31,14 @@ #include "being/localplayer.h" -#include "gui/ministatuswindow.h" -#include "gui/okdialog.h" -#include "gui/npcdialog.h" -#include "gui/skilldialog.h" -#include "gui/statuswindow.h" #include "gui/viewport.h" +#include "gui/windows/ministatuswindow.h" +#include "gui/windows/okdialog.h" +#include "gui/windows/npcdialog.h" +#include "gui/windows/skilldialog.h" +#include "gui/windows/statuswindow.h" + #include "resources/deaddb.h" #include "net/net.h" diff --git a/src/net/ea/skillhandler.cpp b/src/net/ea/skillhandler.cpp index 47dc2c2d4..34848077a 100644 --- a/src/net/ea/skillhandler.cpp +++ b/src/net/ea/skillhandler.cpp @@ -29,7 +29,7 @@ #include "being/localplayer.h" #include "being/playerinfo.h" -#include "gui/skilldialog.h" +#include "gui/windows/skilldialog.h" #include "utils/stringutils.h" diff --git a/src/net/ea/tradehandler.cpp b/src/net/ea/tradehandler.cpp index 3e1e5c5b3..abfb56559 100644 --- a/src/net/ea/tradehandler.cpp +++ b/src/net/ea/tradehandler.cpp @@ -31,8 +31,8 @@ #include "being/playerinfo.h" #include "being/playerrelations.h" -#include "gui/confirmdialog.h" -#include "gui/tradewindow.h" +#include "gui/windows/confirmdialog.h" +#include "gui/windows/tradewindow.h" #include "net/inventoryhandler.h" #include "net/net.h" diff --git a/src/net/eathena/beinghandler.cpp b/src/net/eathena/beinghandler.cpp index 1833c9a87..f136abfeb 100644 --- a/src/net/eathena/beinghandler.cpp +++ b/src/net/eathena/beinghandler.cpp @@ -32,9 +32,10 @@ #include "input/keyboardconfig.h" -#include "gui/outfitwindow.h" -#include "gui/socialwindow.h" -#include "gui/killstats.h" +#include "gui/windows/socialwindow.h" +#include "gui/windows/killstats.h" + +#include "gui/windows/outfitwindow.h" #include "net/eathena/messageout.h" #include "net/eathena/protocol.h" diff --git a/src/net/eathena/buysellhandler.cpp b/src/net/eathena/buysellhandler.cpp index 44c8eb125..361fe89a0 100644 --- a/src/net/eathena/buysellhandler.cpp +++ b/src/net/eathena/buysellhandler.cpp @@ -27,7 +27,7 @@ #include "being/playerinfo.h" -#include "gui/buydialog.h" +#include "gui/windows/buydialog.h" #include "net/ea/eaprotocol.h" diff --git a/src/net/eathena/generalhandler.cpp b/src/net/eathena/generalhandler.cpp index 4f1edd971..f6657db36 100644 --- a/src/net/eathena/generalhandler.cpp +++ b/src/net/eathena/generalhandler.cpp @@ -26,10 +26,10 @@ #include "configuration.h" #include "logger.h" -#include "gui/inventorywindow.h" -#include "gui/skilldialog.h" -#include "gui/socialwindow.h" -#include "gui/statuswindow.h" +#include "gui/windows/inventorywindow.h" +#include "gui/windows/skilldialog.h" +#include "gui/windows/socialwindow.h" +#include "gui/windows/statuswindow.h" #include "net/ea/guildhandler.h" diff --git a/src/net/eathena/npchandler.cpp b/src/net/eathena/npchandler.cpp index b0066b561..8ca545adf 100644 --- a/src/net/eathena/npchandler.cpp +++ b/src/net/eathena/npchandler.cpp @@ -24,7 +24,7 @@ #include "being/localplayer.h" -#include "gui/npcdialog.h" +#include "gui/windows/npcdialog.h" #include "net/eathena/messageout.h" #include "net/eathena/protocol.h" diff --git a/src/net/tmwa/buysellhandler.cpp b/src/net/tmwa/buysellhandler.cpp index 08719e0b6..4fc80acb1 100644 --- a/src/net/tmwa/buysellhandler.cpp +++ b/src/net/tmwa/buysellhandler.cpp @@ -27,7 +27,7 @@ #include "being/playerinfo.h" -#include "gui/buydialog.h" +#include "gui/windows/buydialog.h" #include "net/ea/eaprotocol.h" diff --git a/src/net/tmwa/generalhandler.cpp b/src/net/tmwa/generalhandler.cpp index cb01e6509..d2fe22c62 100644 --- a/src/net/tmwa/generalhandler.cpp +++ b/src/net/tmwa/generalhandler.cpp @@ -26,10 +26,10 @@ #include "configuration.h" #include "logger.h" -#include "gui/inventorywindow.h" -#include "gui/skilldialog.h" -#include "gui/socialwindow.h" -#include "gui/statuswindow.h" +#include "gui/windows/inventorywindow.h" +#include "gui/windows/skilldialog.h" +#include "gui/windows/socialwindow.h" +#include "gui/windows/statuswindow.h" #include "net/ea/guildhandler.h" diff --git a/src/net/tmwa/npchandler.cpp b/src/net/tmwa/npchandler.cpp index 026727a6e..d03cd4fb5 100644 --- a/src/net/tmwa/npchandler.cpp +++ b/src/net/tmwa/npchandler.cpp @@ -24,9 +24,10 @@ #include "being/localplayer.h" -#include "gui/npcdialog.h" #include "gui/viewport.h" +#include "gui/windows/npcdialog.h" + #include "net/tmwa/messageout.h" #include "net/tmwa/protocol.h" diff --git a/src/net/tmwa/playerhandler.cpp b/src/net/tmwa/playerhandler.cpp index dc6244f43..0361e125d 100644 --- a/src/net/tmwa/playerhandler.cpp +++ b/src/net/tmwa/playerhandler.cpp @@ -31,7 +31,7 @@ #include "net/tmwa/messageout.h" #include "net/tmwa/protocol.h" -#include "gui/whoisonline.h" +#include "gui/windows/whoisonline.h" #include "debug.h" diff --git a/src/net/tmwa/questhandler.cpp b/src/net/tmwa/questhandler.cpp index 4df7f06ce..ca9a2c9f1 100644 --- a/src/net/tmwa/questhandler.cpp +++ b/src/net/tmwa/questhandler.cpp @@ -20,8 +20,8 @@ #include "net/tmwa/questhandler.h" -#include "gui/skilldialog.h" -#include "gui/questswindow.h" +#include "gui/windows/skilldialog.h" +#include "gui/windows/questswindow.h" #include "net/tmwa/protocol.h" diff --git a/src/spellmanager.cpp b/src/spellmanager.cpp index 91cfb1ff2..c8f6fd836 100644 --- a/src/spellmanager.cpp +++ b/src/spellmanager.cpp @@ -27,7 +27,7 @@ #include "being/localplayer.h" #include "being/playerinfo.h" -#include "gui/chatwindow.h" +#include "gui/windows/chatwindow.h" #include "net/net.h" #include "net/playerhandler.h" -- cgit v1.2.3-70-g09d2