From 49fcec5759c5b02f918d8ed27fccc71cde1e07c3 Mon Sep 17 00:00:00 2001 From: Sit Melai Date: Thu, 27 Aug 2020 02:30:02 +0200 Subject: [PATCH 1/5] First steps, still work in progress --- .../src/interface_v3/people_interraction.cpp | 56 +++++++++++++++++++ .../client/src/interface_v3/people_list.h | 3 +- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/code/ryzom/client/src/interface_v3/people_interraction.cpp b/code/ryzom/client/src/interface_v3/people_interraction.cpp index 96f27bb6c..91226657e 100644 --- a/code/ryzom/client/src/interface_v3/people_interraction.cpp +++ b/code/ryzom/client/src/interface_v3/people_interraction.cpp @@ -2307,6 +2307,62 @@ public: }; REGISTER_ACTION_HANDLER( CHandlerMoveContact, "move_contact"); +uint lastPeopleIndexChangeGroup; +//================================================================================================================= +class CHandlerChangeContactGroupBegin : public IActionHandler +{ +public: + void execute (CCtrlBase * /* pCaller */, const std::string &sParams) + { + // retrieve the index of the people + CPeopleList *srcList; + if (PeopleInterraction.getPeopleFromCurrentMenu(srcList, lastPeopleIndexChangeGroup)) + { + string groupName= getParam(sParams, "group"); + CInterfaceGroup *gc = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(groupName)); + if (gc) + { + CGroupEditBox *geb = dynamic_cast(gc->getGroup("change_contact_group_eb:eb")); + geb->setInputString(ucstring("")); + } + CAHManager::getInstance()->runActionHandler("enter_modal", pCaller, sParams); + } + } +}; +REGISTER_ACTION_HANDLER( CHandlerMoveContact, "change_contact_group_begin"); + +//================================================================================================================= +// Add a contact to the list +class CHandlerChangeContactGroup : public IActionHandler +{ +public: + void execute (CCtrlBase *pCaller, const std::string &/* sParams */) + { + CInterfaceManager *pIM = CInterfaceManager::getInstance(); + + if (pCaller) + { + // Get the modal edit box + CGroupEditBox *geb = dynamic_cast(CWidgetManager::getInstance()->getElementFromId("ui:interface:change_contact_group_eb:eb")); + if (geb && !geb->getInputString().empty()) + { + // don't add if it is the player name + if (!ClientCfg.Local && (UserEntity->getEntityName() == geb->getInputString())) + { + displayVisibleSystemMsg(CI18N::get("uiCantAddYourSelfInContactList")); + } + else + { + PeopleInterraction.askAddContact(geb->getInputString(), peopleList); + geb->setInputString(ucstring("")); + } + geb->setInputString(ucstring("")); + } + } + CAHManager::getInstance()->runActionHandler("leave_modal", pCaller, ""); + } +}; +REGISTER_ACTION_HANDLER( CHandlerAddContact, "change_contact_group"); //================================================================================================================= class CHandlerSortContacts : public IActionHandler diff --git a/code/ryzom/client/src/interface_v3/people_list.h b/code/ryzom/client/src/interface_v3/people_list.h index 32317b6b8..6845ce73a 100644 --- a/code/ryzom/client/src/interface_v3/people_list.h +++ b/code/ryzom/client/src/interface_v3/people_list.h @@ -151,13 +151,14 @@ public: private: struct CPeople { - CPeople() : Container(NULL), Chat(NULL), Online(ccs_offline), Blocked(false), ContactId(0) {} + CPeople() : Container(NULL), Chat(NULL), Online(ccs_offline), Blocked(false), ContactId(0), Group("") {} NLMISC::CRefPtr Container; // todo : replace this with a CChatWindow one day, for consistency NLMISC::CRefPtr Chat; uint GlobalID; TCharConnectionState Online; bool Blocked; uint32 ContactId; + ucstring Group; bool operator < (const CPeople &other) const { return getName() < other.getName(); } ucstring getName() const { return Container->getUCTitle(); } }; From 5dc85db8b114d5d21993b1c48200cd599688f438 Mon Sep 17 00:00:00 2001 From: Sit Melai Date: Tue, 1 Sep 2020 15:29:02 +0200 Subject: [PATCH 2/5] Added action handlers to change contact group and read/write to file --- .../src/interface_v3/people_interraction.cpp | 517 +++++++++--------- .../client/src/interface_v3/people_list.cpp | 340 +++++++++--- .../client/src/interface_v3/people_list.h | 6 + 3 files changed, 525 insertions(+), 338 deletions(-) diff --git a/code/ryzom/client/src/interface_v3/people_interraction.cpp b/code/ryzom/client/src/interface_v3/people_interraction.cpp index 91226657e..9164a78ea 100644 --- a/code/ryzom/client/src/interface_v3/people_interraction.cpp +++ b/code/ryzom/client/src/interface_v3/people_interraction.cpp @@ -90,7 +90,7 @@ static const sint PARTY_CHAT_SPAWN_DELTA = 20; // to avoid that all party chat a ////////////////////////////////// /** Display an error msg in the system info window, and also in the last window that triggered the command (so that the user is sure to see it) - */ + */ static void displayVisibleSystemMsg(const ucstring &msg, const string &cat = "CHK"); @@ -289,13 +289,13 @@ void CChatStdInput::registerListeningWindow(CChatWindow *cw) //=========================================================================================================== CPeopleInterraction::CPeopleInterraction() : Region(NULL), - Universe(NULL), - TeamChat(NULL), - GuildChat(NULL), - SystemInfo(NULL), - TellWindow(NULL), - DebugInfo(NULL), - CurrPartyChatID(0) + Universe(NULL), + TeamChat(NULL), + GuildChat(NULL), + SystemInfo(NULL), + TellWindow(NULL), + DebugInfo(NULL), + CurrPartyChatID(0) { for(uint i=0;isetMenu("ui:interface:base_chat_box_menu"); */ + chatDesc.FatherContainer = "ui:interface"; + chatDesc.Title = "uiTellWindow"; + chatDesc.Listener = NULL; + chatDesc.Savable = true; + chatDesc.Localize = true; + chatDesc.Id = "tell"; + chatDesc.ChatTemplate ="chat_no_eb_id"; + chatDesc.AHOnActive = "set"; + chatDesc.AHOnActiveParams = "dblink=UI:SAVE:ISDETACHED:TELL|value=1"; + chatDesc.AHOnDeactive = "set"; + chatDesc.AHOnDeactiveParams = "dblink=UI:SAVE:ISDETACHED:TELL|value=0"; + + TellWindow = getChatWndMgr().createChatWindow(chatDesc); + if (!TellWindow) return; + TellWindow->setMenu("ui:interface:base_chat_box_menu"); */ } //=========================================================================================================== @@ -826,13 +828,13 @@ class CHandlerUserChatActive : public IActionHandler CChatGroup::TGroupType m = PeopleInterraction.TheUserChat.Filter.getTargetGroup(); switch(m) { - default: - case CChatGroup::arround: - case CChatGroup::say: pUserBut->setHardText("uiFilterAround"); break; - case CChatGroup::region: pUserBut->setHardText("uiFilterRegion"); break; - case CChatGroup::universe: pUserBut->setHardText("uiFilterUniverse"); break; - case CChatGroup::team: pUserBut->setHardText("uiFilterTeam"); break; - case CChatGroup::guild: pUserBut->setHardText("uiFilterGuild"); break; + default: + case CChatGroup::arround: + case CChatGroup::say: pUserBut->setHardText("uiFilterAround"); break; + case CChatGroup::region: pUserBut->setHardText("uiFilterRegion"); break; + case CChatGroup::universe: pUserBut->setHardText("uiFilterUniverse"); break; + case CChatGroup::team: pUserBut->setHardText("uiFilterTeam"); break; + case CChatGroup::guild: pUserBut->setHardText("uiFilterGuild"); break; } pUserBut->getParent()->updateCoords(); pUserBut->updateCoords(); @@ -925,29 +927,29 @@ class CHandlerChatGroupFilter : public IActionHandler CChatGroup::TGroupType m = PeopleInterraction.TheUserChat.Filter.getTargetGroup(); switch(m) { - default: - case CChatGroup::arround: - case CChatGroup::say: pUserBut->setHardText("uiFilterAround"); break; - case CChatGroup::region: pUserBut->setHardText("uiFilterRegion"); break; - case CChatGroup::team: pUserBut->setHardText("uiFilterTeam"); break; - case CChatGroup::guild: pUserBut->setHardText("uiFilterGuild"); break; - case CChatGroup::universe: pUserBut->setHardText("uiFilterUniverse"); break; - case CChatGroup::dyn_chat: - uint32 index = PeopleInterraction.TheUserChat.Filter.getTargetDynamicChannelDbIndex(); - uint32 textId = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:DYN_CHAT:CHANNEL"+toString(index)+":NAME")->getValue32(); - ucstring title; - STRING_MANAGER::CStringManagerClient::instance()->getDynString(textId, title); - if (title.empty()) - { - // Dyn channel not available yet, so set to around - PeopleInterraction.TheUserChat.Filter.setTargetGroup(CChatGroup::arround); - pUserBut->setHardText("uiFilterAround"); - } - else - { - pUserBut->setHardText(title.toUtf8()); - } - break; + default: + case CChatGroup::arround: + case CChatGroup::say: pUserBut->setHardText("uiFilterAround"); break; + case CChatGroup::region: pUserBut->setHardText("uiFilterRegion"); break; + case CChatGroup::team: pUserBut->setHardText("uiFilterTeam"); break; + case CChatGroup::guild: pUserBut->setHardText("uiFilterGuild"); break; + case CChatGroup::universe: pUserBut->setHardText("uiFilterUniverse"); break; + case CChatGroup::dyn_chat: + uint32 index = PeopleInterraction.TheUserChat.Filter.getTargetDynamicChannelDbIndex(); + uint32 textId = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:DYN_CHAT:CHANNEL"+toString(index)+":NAME")->getValue32(); + ucstring title; + STRING_MANAGER::CStringManagerClient::instance()->getDynString(textId, title); + if (title.empty()) + { + // Dyn channel not available yet, so set to around + PeopleInterraction.TheUserChat.Filter.setTargetGroup(CChatGroup::arround); + pUserBut->setHardText("uiFilterAround"); + } + else + { + pUserBut->setHardText(title.toUtf8()); + } + break; } pUserBut->setActive(true); @@ -1252,8 +1254,8 @@ void CPeopleInterraction::askRemoveContact(uint peopleIndex, CPeopleList *pl) //================================================================================================================= void CPeopleInterraction::initContactLists( const std::vector &vFriendListName, - const std::vector &vFriendListOnline, - const std::vector &vIgnoreListName ) + const std::vector &vFriendListOnline, + const std::vector &vIgnoreListName ) { // clear the current lists if any @@ -1266,6 +1268,9 @@ void CPeopleInterraction::initContactLists( const std::vector &vFriendLi addContactInList(contactIdPool++, vFriendListName[i], vFriendListOnline[i], 0); for (uint i = 0; i < vIgnoreListName.size(); ++i) addContactInList(contactIdPool++, vIgnoreListName[i], ccs_offline, 1); + FriendList.readContactGroups(); + CPeopleList::TSortOrder order = (CPeopleList::TSortOrder)(NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CONTACT_LIST:SORT_ORDER")->getValue32()); + FriendList.sortEx(order); updateAllFreeTellerHeaders(); } @@ -1278,6 +1283,8 @@ void CPeopleInterraction::addContactInList(uint32 contactId, const ucstring &nam // remove the shard name if possible ucstring name= CEntityCL::removeShardFromName(nameIn); + + // add the contact to this list sint index = pl.getIndexFromName(name); // try to create if not found @@ -1477,7 +1484,7 @@ bool CPeopleInterraction::testValidPartyChatName(const ucstring &title) index = IgnoreList.getIndexFromName(title); if (index != -1) return false; // TODO_GAMEDEV server test for the name (not only local), & modify callers of this function - // The party chat should NOT have the name of a player + // The party chat should NOT have the name of a player // A player name is NOT valid if it is the same that a party chat name return true; } @@ -1547,14 +1554,14 @@ bool CPeopleInterraction::createNewPartyChat(const ucstring &title) { // popup the container /* - newPartyChat->getContainer()->setup(); - newPartyChat->getContainer()->setOpen(true); - newPartyChat->getContainer()->popupCurrentPos(); - newPartyChat->getContainer()->updateCoords(); - newPartyChat->getContainer()->center(); - newPartyChat->getContainer()->setX(newPartyChat->getContainer()->getX() + (sint32) (rand() % PARTY_CHAT_SPAWN_DELTA)); - newPartyChat->getContainer()->setY(newPartyChat->getContainer()->getY() + (sint32) (rand() % PARTY_CHAT_SPAWN_DELTA)); - newPartyChat->getContainer()->enableBlink(2); + newPartyChat->getContainer()->setup(); + newPartyChat->getContainer()->setOpen(true); + newPartyChat->getContainer()->popupCurrentPos(); + newPartyChat->getContainer()->updateCoords(); + newPartyChat->getContainer()->center(); + newPartyChat->getContainer()->setX(newPartyChat->getContainer()->getX() + (sint32) (rand() % PARTY_CHAT_SPAWN_DELTA)); + newPartyChat->getContainer()->setY(newPartyChat->getContainer()->getY() + (sint32) (rand() % PARTY_CHAT_SPAWN_DELTA)); + newPartyChat->getContainer()->enableBlink(2); */ CPartyChatInfo pci; @@ -1742,15 +1749,15 @@ bool CPeopleInterraction::loadUserChatsInfos(NLMISC::IStream &f) f.serialCheck(NELID("TAHC")); if (ver>=1) { -// CChatGroupWindow *pCGW = PeopleInterraction.getChatGroupWindow(); + // CChatGroupWindow *pCGW = PeopleInterraction.getChatGroupWindow(); sint32 index; f.serial(index); /* Yoyo: decide to always start with the default channel (user) activated - because complex (at this time, the buttons are not all active, must wait guild loading, UI:SAVE loading etc...) - Hence this doesn't work for anything but User and Sysinfo (if it is activated....) - NB: must still load the index for file format reason - //if (pCGW) pCGW->setTabIndex(index); - */ + because complex (at this time, the buttons are not all active, must wait guild loading, UI:SAVE loading etc...) + Hence this doesn't work for anything but User and Sysinfo (if it is activated....) + NB: must still load the index for file format reason + //if (pCGW) pCGW->setTabIndex(index); + */ f.serial(present); if (present) { @@ -2012,17 +2019,17 @@ public: if (list == &PeopleInterraction.TeamList) // check for good list { /* - const string msgName = "TEAM:SET_LEADER"; - CBitMemStream out; - if(GenericMsgHeaderMngr.pushNameToStream(msgName, out)) - { - uint8 teamMember = (uint8)(peopleIndex); - out.serial(teamMember); - NetMngr.push(out); - //nlinfo("impulseCallBack : %s %d sent", msgName.c_str(), teamMember); - } - else - nlwarning("command 'set_leader': unknown message named '%s'.", msgName.c_str()); + const string msgName = "TEAM:SET_LEADER"; + CBitMemStream out; + if(GenericMsgHeaderMngr.pushNameToStream(msgName, out)) + { + uint8 teamMember = (uint8)(peopleIndex); + out.serial(teamMember); + NetMngr.push(out); + //nlinfo("impulseCallBack : %s %d sent", msgName.c_str(), teamMember); + } + else + nlwarning("command 'set_leader': unknown message named '%s'.", msgName.c_str()); */ NLMISC::ICommand::execute("a setTeamLeader " + toString(peopleIndex), g_log); } @@ -2177,8 +2184,8 @@ public: void execute (CCtrlBase *pCaller, const std::string &sParams) { /** This msg may have been triggered from valid button or from the edit box itself, so retrieve - * the edit box from the enclosing group - */ + * the edit box from the enclosing group + */ // Get enclosing container to know in which people list we are if (pCaller) { @@ -2221,8 +2228,8 @@ public: CInterfaceManager *pIM = CInterfaceManager::getInstance(); /** This msg may have been triggered from valid button or from the edit box itself, so retrieve - * the edit box from the enclosing group - */ + * the edit box from the enclosing group + */ // Get enclosing container to know in which people list we are if (!LastFatherAddContactId.empty() && pCaller) { @@ -2292,13 +2299,13 @@ public: } switch(listIndex) { - case 0: - destList = &PeopleInterraction.IgnoreList; + case 0: + destList = &PeopleInterraction.IgnoreList; break; - case 1: - destList = &PeopleInterraction.FriendList; + case 1: + destList = &PeopleInterraction.FriendList; break; - default: nlwarning("Bad list index"); return; + default: nlwarning("Bad list index"); return; } PeopleInterraction.askMoveContact(peopleIndex, srcList, destList); @@ -2312,7 +2319,7 @@ uint lastPeopleIndexChangeGroup; class CHandlerChangeContactGroupBegin : public IActionHandler { public: - void execute (CCtrlBase * /* pCaller */, const std::string &sParams) + void execute (CCtrlBase * pCaller, const std::string &sParams) { // retrieve the index of the people CPeopleList *srcList; @@ -2321,18 +2328,18 @@ public: string groupName= getParam(sParams, "group"); CInterfaceGroup *gc = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(groupName)); if (gc) - { - CGroupEditBox *geb = dynamic_cast(gc->getGroup("change_contact_group_eb:eb")); - geb->setInputString(ucstring("")); - } + { + CGroupEditBox *geb = dynamic_cast(gc->getGroup("change_contact_group_eb:eb")); + geb->setInputString(ucstring("")); + } CAHManager::getInstance()->runActionHandler("enter_modal", pCaller, sParams); } } }; -REGISTER_ACTION_HANDLER( CHandlerMoveContact, "change_contact_group_begin"); +REGISTER_ACTION_HANDLER( CHandlerChangeContactGroupBegin, "change_contact_group_begin"); //================================================================================================================= -// Add a contact to the list +// Change the group of a contact in the list class CHandlerChangeContactGroup : public IActionHandler { public: @@ -2343,26 +2350,20 @@ public: if (pCaller) { // Get the modal edit box - CGroupEditBox *geb = dynamic_cast(CWidgetManager::getInstance()->getElementFromId("ui:interface:change_contact_group_eb:eb")); - if (geb && !geb->getInputString().empty()) + CGroupEditBox *geb = dynamic_cast(CWidgetManager::getInstance()->getElementFromId("ui:interface:change_contact_group:change_contact_group_eb:eb")); + if (geb) { - // don't add if it is the player name - if (!ClientCfg.Local && (UserEntity->getEntityName() == geb->getInputString())) - { - displayVisibleSystemMsg(CI18N::get("uiCantAddYourSelfInContactList")); - } - else - { - PeopleInterraction.askAddContact(geb->getInputString(), peopleList); - geb->setInputString(ucstring("")); - } + + PeopleInterraction.FriendList.changeGroup(lastPeopleIndexChangeGroup, geb->getInputString()); geb->setInputString(ucstring("")); + CPeopleList::TSortOrder order = (CPeopleList::TSortOrder)(NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CONTACT_LIST:SORT_ORDER")->getValue32()); + PeopleInterraction.FriendList.sortEx(order); } } CAHManager::getInstance()->runActionHandler("leave_modal", pCaller, ""); } }; -REGISTER_ACTION_HANDLER( CHandlerAddContact, "change_contact_group"); +REGISTER_ACTION_HANDLER( CHandlerChangeContactGroup, "change_contact_group"); //================================================================================================================= class CHandlerSortContacts : public IActionHandler @@ -2428,7 +2429,7 @@ REGISTER_ACTION_HANDLER( CHandlerContactDirectChat, "contact_direct_chat"); //================================================================================================================= /** Menu to create a new party chat - */ + */ class CHandlerNewPartyChat : public IActionHandler { public: @@ -2462,7 +2463,7 @@ REGISTER_ACTION_HANDLER( CHandlerNewPartyChat, "new_party_chat"); //================================================================================================================= /** The name of a party chat has been validated - */ + */ class CHandlerValidatePartyChatName : public IActionHandler { void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */) @@ -2495,12 +2496,12 @@ REGISTER_ACTION_HANDLER(CHandlerValidatePartyChatName, "validate_party_chat_name //================================================================================================================= /** Menu to create a new party chat - */ + */ //================================================================================================================= /** Menu to remove a currenlty created party chat - */ + */ class CHandlerRemovePartyChat : public IActionHandler { void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */) @@ -2513,7 +2514,7 @@ REGISTER_ACTION_HANDLER( CHandlerRemovePartyChat, "remove_party_chat"); //================================================================================================================= /** TEMP : just create an 'invite' command in the 'around me' edit box - */ + */ class CHandlerPartyChatInvite : public IActionHandler { void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */) @@ -2539,12 +2540,12 @@ REGISTER_ACTION_HANDLER( CHandlerPartyChatInvite, "party_chat_invite" ); //================================================================================================================= /** Add all members of the team to the party chat - */ + */ class CHandlerAddAllTeamMembersToPartyChat : public IActionHandler { void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */) { -// CChatWindow *chat = getChatWndMgr().getChatWindowFromCaller(CWidgetManager::getInstance()->getCtrlLaunchingModal()); + // CChatWindow *chat = getChatWndMgr().getChatWindowFromCaller(CWidgetManager::getInstance()->getCtrlLaunchingModal()); // TODO GAMEDEV : add all team members } }; @@ -2552,12 +2553,12 @@ REGISTER_ACTION_HANDLER( CHandlerAddAllTeamMembersToPartyChat, "add_all_team_mem //================================================================================================================= /** Remove all members of the team to the party chat - */ + */ class CHandlerRemoveAllTeamMembersToPartyChat : public IActionHandler { void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */) { -// CChatWindow *chat = getChatWndMgr().getChatWindowFromCaller(CWidgetManager::getInstance()->getCtrlLaunchingModal()); + // CChatWindow *chat = getChatWndMgr().getChatWindowFromCaller(CWidgetManager::getInstance()->getCtrlLaunchingModal()); // TODO GAMEDEV : remove all team members } }; @@ -2565,12 +2566,12 @@ REGISTER_ACTION_HANDLER( CHandlerRemoveAllTeamMembersToPartyChat, "remove_all_te //================================================================================================================= /** Add all members of the guild to the party chat - */ + */ class CHandlerAddAllGuildMembersToPartyChat : public IActionHandler { void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */) { -// CChatWindow *chat = getChatWndMgr().getChatWindowFromCaller(CWidgetManager::getInstance()->getCtrlLaunchingModal()); + // CChatWindow *chat = getChatWndMgr().getChatWindowFromCaller(CWidgetManager::getInstance()->getCtrlLaunchingModal()); // TODO GAMEDEV : add all guild members } }; @@ -2578,12 +2579,12 @@ REGISTER_ACTION_HANDLER( CHandlerAddAllGuildMembersToPartyChat, "add_all_guild_m //================================================================================================================= /** Remove all members of the team to the party chat - */ + */ class CHandlerRemoveAllGuildMembersToPartyChat : public IActionHandler { void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */) { -// CChatWindow *chat = getChatWndMgr().getChatWindowFromCaller(CWidgetManager::getInstance()->getCtrlLaunchingModal()); + // CChatWindow *chat = getChatWndMgr().getChatWindowFromCaller(CWidgetManager::getInstance()->getCtrlLaunchingModal()); // TODO_GAMEDEV : remove all guild members } }; @@ -2595,8 +2596,8 @@ REGISTER_ACTION_HANDLER( CHandlerRemoveAllGuildMembersToPartyChat, "remove_all_g //================================================================================================================= /** Select the target on a filtered chat window - * This create a menu with the standard window (team, around me ...) + the party chat windows - */ + * This create a menu with the standard window (team, around me ...) + the party chat windows + */ class CHandlerSelectChatTarget : public IActionHandler { public: @@ -2659,7 +2660,7 @@ public: { CInterfaceManager *pIM = CInterfaceManager::getInstance(); cw = PeopleInterraction.TheUserChat.Window; -// CChatStdInput &ci = PeopleInterraction.ChatInput; + // CChatStdInput &ci = PeopleInterraction.ChatInput; CGroupMenu *pMenu = dynamic_cast(CWidgetManager::getInstance()->getElementFromId("ui:interface:user_chat_target_menu")); CViewTextMenu *pMenuAround = dynamic_cast(pMenu->getElement("ui:interface:user_chat_target_menu:around")); CViewTextMenu *pMenuRegion = dynamic_cast(pMenu->getElement("ui:interface:user_chat_target_menu:region")); @@ -2715,7 +2716,7 @@ REGISTER_ACTION_HANDLER( CHandlerSelectChatTarget, "select_chat_target"); //================================================================================================================= /** A target has been selected for a filtered chat - */ + */ class CHandlerChatTargetSelected : public IActionHandler { void execute (CCtrlBase * /* pCaller */, const std::string &sParams) @@ -2804,7 +2805,7 @@ REGISTER_ACTION_HANDLER( CHandlerChatTargetSelected, "chat_target_selected"); //================================================================================================================= /** If no more in team, leave team chat mode - */ + */ class CHandlerLeaveTeamChat : public IActionHandler { void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */) @@ -2829,7 +2830,7 @@ REGISTER_ACTION_HANDLER( CHandlerLeaveTeamChat, "leave_team_chat"); /** Create checkbox for a menu. - */ + */ static CInterfaceGroup *createMenuCheckBox(const std::string &onclickL, const std::string ¶msL, bool checked) { pair params [2]; @@ -2851,7 +2852,7 @@ static CInterfaceGroup *createMenuCheckBox(const std::string &onclickL, const st //================================================================================================================= /** Display a menu to select the source on a filtered chat - */ + */ class CHandlerSelectChatSource : public IActionHandler { void execute (CCtrlBase *pCaller, const std::string &/* sParams */) @@ -3033,7 +3034,7 @@ REGISTER_ACTION_HANDLER(CHandlerSelectChatSource, "select_chat_source"); //================================================================================================================= /** A new source has been selected / unselected from a filtered chat - */ + */ class CHandlerChatSourceSelected : public IActionHandler { void execute (CCtrlBase * /* pCaller */, const std::string &sParams) @@ -3057,10 +3058,10 @@ class CHandlerChatSourceSelected : public IActionHandler /*CCtrlBaseButton *button = dynamic_cast(pCaller); - if (button) - { - button->setPushed(!button->getPushed()); - }*/ + if (button) + { + button->setPushed(!button->getPushed()); + }*/ // GUILD if (nlstricmp(sParams, "guild") == 0) { @@ -3068,71 +3069,71 @@ class CHandlerChatSourceSelected : public IActionHandler else ci.Guild.addListeningWindow(cw); } else - // TEAM - if (nlstricmp(sParams, "team") == 0) - { - if (ci.Team.isListeningWindow(cw)) ci.Team.removeListeningWindow(cw); - else ci.Team.addListeningWindow(cw); - } - else - // AROUND ME - if (nlstricmp(sParams, "am") == 0) - { - if (ci.AroundMe.isListeningWindow(cw)) ci.AroundMe.removeListeningWindow(cw); - else ci.AroundMe.addListeningWindow(cw); - } - else - // REGION - if (nlstricmp(sParams, "region") == 0) - { - if (ci.Region.isListeningWindow(cw)) ci.Region.removeListeningWindow(cw); - else ci.Region.addListeningWindow(cw); - } - else - // UNIVERSE - if (nlstricmp(sParams, "universe") == 0) - { - if (ci.Universe.isListeningWindow(cw)) ci.Universe.removeListeningWindow(cw); - else ci.Universe.addListeningWindow(cw); - } - else - // TELL - if (nlstricmp(sParams, "tell") == 0) - { - if (ci.Tell.isListeningWindow(cw)) ci.Tell.removeListeningWindow(cw); - else ci.Tell.addListeningWindow(cw); - } - else - // SYSTEM INFOS - if (nlstricmp(sParams, "si") == 0) - { - if (ci.SystemInfo.isListeningWindow(cw)) ci.SystemInfo.removeListeningWindow(cw); - else ci.SystemInfo.addListeningWindow(cw); - } - else - // PARTY CHAT - if (fromString(sParams, partyChatID)) - { - std::vector &partyChats = PeopleInterraction.PartyChats; - for(uint k = 0; k < partyChats.size(); ++k) + // TEAM + if (nlstricmp(sParams, "team") == 0) { - if (partyChats[k].ID == (uint) partyChatID) + if (ci.Team.isListeningWindow(cw)) ci.Team.removeListeningWindow(cw); + else ci.Team.addListeningWindow(cw); + } + else + // AROUND ME + if (nlstricmp(sParams, "am") == 0) { - if (partyChats[k].Filter != NULL) + if (ci.AroundMe.isListeningWindow(cw)) ci.AroundMe.removeListeningWindow(cw); + else ci.AroundMe.addListeningWindow(cw); + } + else + // REGION + if (nlstricmp(sParams, "region") == 0) { - if (partyChats[k].Filter->isListeningWindow(cw)) partyChats[k].Filter->removeListeningWindow(partyChats[k].Window); - else partyChats[k].Filter->addListeningWindow(cw); + if (ci.Region.isListeningWindow(cw)) ci.Region.removeListeningWindow(cw); + else ci.Region.addListeningWindow(cw); } - } - } - } - else if (nlstricmp(sParams.substr(0, 3), "dyn") == 0) - { - uint8 i = 0; - fromString(sParams.substr(3), i); - if (ci.DynamicChat[i].isListeningWindow(cw)) ci.DynamicChat[i].removeListeningWindow(cw); - else ci.DynamicChat[i].addListeningWindow(cw); - } + else + // UNIVERSE + if (nlstricmp(sParams, "universe") == 0) + { + if (ci.Universe.isListeningWindow(cw)) ci.Universe.removeListeningWindow(cw); + else ci.Universe.addListeningWindow(cw); + } + else + // TELL + if (nlstricmp(sParams, "tell") == 0) + { + if (ci.Tell.isListeningWindow(cw)) ci.Tell.removeListeningWindow(cw); + else ci.Tell.addListeningWindow(cw); + } + else + // SYSTEM INFOS + if (nlstricmp(sParams, "si") == 0) + { + if (ci.SystemInfo.isListeningWindow(cw)) ci.SystemInfo.removeListeningWindow(cw); + else ci.SystemInfo.addListeningWindow(cw); + } + else + // PARTY CHAT + if (fromString(sParams, partyChatID)) + { + std::vector &partyChats = PeopleInterraction.PartyChats; + for(uint k = 0; k < partyChats.size(); ++k) + { + if (partyChats[k].ID == (uint) partyChatID) + { + if (partyChats[k].Filter != NULL) + { + if (partyChats[k].Filter->isListeningWindow(cw)) partyChats[k].Filter->removeListeningWindow(partyChats[k].Window); + else partyChats[k].Filter->addListeningWindow(cw); + } + } + } + } + else if (nlstricmp(sParams.substr(0, 3), "dyn") == 0) + { + uint8 i = 0; + fromString(sParams.substr(3), i); + if (ci.DynamicChat[i].isListeningWindow(cw)) ci.DynamicChat[i].removeListeningWindow(cw); + else ci.DynamicChat[i].addListeningWindow(cw); + } } }; REGISTER_ACTION_HANDLER( CHandlerChatSourceSelected, "chat_source_selected"); @@ -3242,80 +3243,80 @@ NLMISC_COMMAND(ignore, "add or remove a player from the ignore list", "") { - if (args.size() != 1) - { - displayVisibleSystemMsg(CI18N::get("uiPartyChatCmd")); - return true; - } - CPeopleInterraction &pi = PeopleInterraction; - ucstring title = args[0]; +if (args.size() != 1) +{ +displayVisibleSystemMsg(CI18N::get("uiPartyChatCmd")); +return true; +} +CPeopleInterraction &pi = PeopleInterraction; +ucstring title = args[0]; - if (!pi.testValidPartyChatName(title)) - { - displayVisibleSystemMsg(CI18N::get("uiInvalidPartyChatName")); - return true; - } +if (!pi.testValidPartyChatName(title)) +{ +displayVisibleSystemMsg(CI18N::get("uiInvalidPartyChatName")); +return true; +} - PeopleInterraction.createNewPartyChat(title); - return true; +PeopleInterraction.createNewPartyChat(title); +return true; } // Remove the party chat with the given name NLMISC_COMMAND(remove_party_chat, "Remove a party chat", "") { - if (args.size() != 1) - { - displayVisibleSystemMsg(CI18N::get("uiRemovePartyChatCmd")); - return true; - } - ucstring title = ucstring(args[0]); - CChatWindow *chat = getChatWndMgr().getChatWindow(title); - if (!chat) - { - displayVisibleSystemMsg(title + ucstring(" : ") + CI18N::get("uiBadPartyChatName")); - return true; - } - if (!PeopleInterraction.removePartyChat(chat)) - { - displayVisibleSystemMsg(title + ucstring(" : ") + CI18N::get("uiCantRemovePartyChat")); - return true; - } - return true; +if (args.size() != 1) +{ +displayVisibleSystemMsg(CI18N::get("uiRemovePartyChatCmd")); +return true; +} +ucstring title = ucstring(args[0]); +CChatWindow *chat = getChatWndMgr().getChatWindow(title); +if (!chat) +{ +displayVisibleSystemMsg(title + ucstring(" : ") + CI18N::get("uiBadPartyChatName")); +return true; +} +if (!PeopleInterraction.removePartyChat(chat)) +{ +displayVisibleSystemMsg(title + ucstring(" : ") + CI18N::get("uiCantRemovePartyChat")); +return true; +} +return true; } // Join a party chat whose name is known NLMISC_COMMAND(add_to_party_chat, "Join the given party chat", "") { - if (args.size() != 1) - { - displayVisibleSystemMsg(CI18N::get("uiAddPartyChatCmd")); - return true; - } - // TODO GAMEDEV : join the party chat - return true; +if (args.size() != 1) +{ +displayVisibleSystemMsg(CI18N::get("uiAddPartyChatCmd")); +return true; +} +// TODO GAMEDEV : join the party chat +return true; } // Invite someone in a party chat NLMISC_COMMAND(invite, "Invite someone to a party chat", " ") { - if (args.size() != 2) - { - displayVisibleSystemMsg(CI18N::get("uiInviteCmd")); - return true; - } - // TODO GAMEDEV : Send invite message to the server - // Check that the inviter has created the chat ? - // The people being invited should receive a popup to announce that he is being invited - return true; +if (args.size() != 2) +{ +displayVisibleSystemMsg(CI18N::get("uiInviteCmd")); +return true; +} +// TODO GAMEDEV : Send invite message to the server +// Check that the inviter has created the chat ? +// The people being invited should receive a popup to announce that he is being invited +return true; } */ diff --git a/code/ryzom/client/src/interface_v3/people_list.cpp b/code/ryzom/client/src/interface_v3/people_list.cpp index 92601ed32..ece5b5cc8 100644 --- a/code/ryzom/client/src/interface_v3/people_list.cpp +++ b/code/ryzom/client/src/interface_v3/people_list.cpp @@ -31,6 +31,7 @@ #include "chat_text_manager.h" #include "people_interraction.h" #include "../user_entity.h" +#include "nel/misc/o_xml.h" using namespace std; using namespace NLMISC; @@ -49,9 +50,9 @@ extern CClientChatManager ChatMngr; //================================================================== CPeopleList::CPeopleList() : _ChatWindow(NULL), - _ContactType(CPeopleListDesc::Unknown), - _CurrPeopleID(0), - _Savable(false) + _ContactType(CPeopleListDesc::Unknown), + _CurrPeopleID(0), + _Savable(false) { // Construct @@ -191,34 +192,41 @@ sint CPeopleList::getIndexFromContainerID(const std::string &id) const //================================================================== bool CPeopleList::sortExByContactId(const CPeople& a, const CPeople& b) { - return (a.ContactId < b.ContactId); + if (a.Group == b.Group) + return (a.ContactId < b.ContactId); + else + return (a.Group < b.Group); } //================================================================== bool CPeopleList::sortExByName(const CPeople& a, const CPeople& b) { - ucstring name_a = toUpper(a.getName()); - ucstring name_b = toUpper(b.getName()); - - return (name_a < name_b); + if (a.Group == b.Group) { + ucstring name_a = toUpper(a.getName()); + ucstring name_b = toUpper(b.getName()); + return (name_a < name_b); + } + else + return (a.Group < b.Group); } //================================================================== bool CPeopleList::sortExByOnline(const CPeople& a, const CPeople& b) { - ucstring name_a = toUpper(a.getName()); - ucstring name_b = toUpper(b.getName()); + if (a.Group == b.Group) { + ucstring name_a = toUpper(a.getName()); + ucstring name_b = toUpper(b.getName()); - // We want order: online/alpha, offworld/alpha, offline/alpha - if (a.Online == b.Online) - { - return (name_a < name_b); - } - else - { - // Compare online status - switch (a.Online) + // We want order: online/alpha, offworld/alpha, offline/alpha + if (a.Online == b.Online) + { + return (name_a < name_b); + } + else { + // Compare online status + switch (a.Online) + { case ccs_online: // a is > if a is online return true; @@ -232,11 +240,11 @@ bool CPeopleList::sortExByOnline(const CPeople& a, const CPeople& b) // b is always > if a is offline return false; break; + } } } - - // Should not get here so just return something - return true; + else + return (a.Group < b.Group); } //================================================================== @@ -245,29 +253,56 @@ void CPeopleList::sortEx(TSortOrder order) // remove all people from the father container if (!_BaseContainer) return; uint k; + for(k = 0; k < _Peoples.size(); ++k) { - _BaseContainer->detachContainer(_Peoples[k].Container); + CGroupContainer *parentContainer = _Peoples[k].Container->getProprietaryContainer(); + parentContainer->detachContainer(_Peoples[k].Container); + } + for (k = 0; k < _GroupContainers.size(); ++k) + { + if (_GroupContainers[k].second->getProprietaryContainer() != NULL) + _BaseContainer->detachContainer(_GroupContainers[k].second); } switch (order) { - default: - case sort_index: - std::sort(_Peoples.begin(), _Peoples.end(), CPeopleList::sortExByContactId); - break; - case sort_name: - std::sort(_Peoples.begin(), _Peoples.end(), CPeopleList::sortExByName); - break; + default: + case sort_index: + std::sort(_Peoples.begin(), _Peoples.end(), CPeopleList::sortExByContactId); + break; + case sort_name: + std::sort(_Peoples.begin(), _Peoples.end(), CPeopleList::sortExByName); + break; - case sort_online: - std::sort(_Peoples.begin(), _Peoples.end(), CPeopleList::sortExByOnline); - break; + case sort_online: + std::sort(_Peoples.begin(), _Peoples.end(), CPeopleList::sortExByOnline); + break; } + CGroupContainer *group = _BaseContainer; + ucstring groupName = ""; + uint groupIndex = 0; + for(k = 0; k < _Peoples.size(); ++k) { - _BaseContainer->attachContainer(_Peoples[k].Container); + bool newGroup = false; + if (k == 0) + { + newGroup = true; + } + while (groupIndex < _GroupContainers.size() && _GroupContainers[groupIndex].first != _Peoples[k].Group.toString()) + { + newGroup = true; + ++groupIndex; + } + if (newGroup && groupIndex < _GroupContainers.size()) + { + group = _GroupContainers[groupIndex].second; + groupName = _GroupContainers[groupIndex].first; + _BaseContainer->attachContainer(group); + } + group->attachContainer(_Peoples[k].Container); } } @@ -299,34 +334,34 @@ bool CPeopleList::isPeopleChatVisible(uint index) const return (_Peoples[index].Chat != NULL); } /* -bool CPeopleList::isPeopleWindowVisible(uint index) const -{ - if (index >= _Peoples.size()) - { - nlwarning("Bad index"); - return false; - } - if (!_Peoples[index].Container) return false; - if (_Peoples[index].Container->isOpen()) - { - CInterfaceGroup *ig = _Peoples[index].Container; - do - { - if (ig->isGroupContainer()) - { - if (!static_cast(ig)->isOpen()) break; - } - if (!ig->getActive()) break; - ig = ig->getParent(); - } - while(ig); - return ig == NULL; // all parent windows must be open & visible - } - else - { - return false; - } -} + bool CPeopleList::isPeopleWindowVisible(uint index) const + { + if (index >= _Peoples.size()) + { + nlwarning("Bad index"); + return false; + } + if (!_Peoples[index].Container) return false; + if (_Peoples[index].Container->isOpen()) + { + CInterfaceGroup *ig = _Peoples[index].Container; + do + { + if (ig->isGroupContainer()) + { + if (!static_cast(ig)->isOpen()) break; + } + if (!ig->getActive()) break; + ig = ig->getParent(); + } + while(ig); + return ig == NULL; // all parent windows must be open & visible + } + else + { + return false; + } + } */ //================================================================== @@ -354,12 +389,12 @@ sint CPeopleList::addPeople(const ucstring &name, uint teamMateIndex /*= 0*/) std::string templateName; switch (_ContactType) { - case CPeopleListDesc::Team: templateName = "mate_id"; break; - case CPeopleListDesc::Contact: templateName = "contact_id_friend"; break; - case CPeopleListDesc::Ignore: templateName = "contact_id_ignore"; break; - default: - nlwarning(" Unknown contact type"); - return -1; + case CPeopleListDesc::Team: templateName = "mate_id"; break; + case CPeopleListDesc::Contact: templateName = "contact_id_friend"; break; + case CPeopleListDesc::Ignore: templateName = "contact_id_ignore"; break; + default: + nlwarning(" Unknown contact type"); + return -1; break; } @@ -379,10 +414,10 @@ sint CPeopleList::addPeople(const ucstring &name, uint teamMateIndex /*= 0*/) gc->setSavable(false); // /*if (_ChatWindow) - { - _ChatWindow->getContainer()->attachContainer(gc); - } - else*/ + { + _ChatWindow->getContainer()->attachContainer(gc); + } + else*/ { _BaseContainer->attachContainer(gc); } @@ -415,8 +450,9 @@ void CPeopleList::removePeople(uint index) } else { - if (_BaseContainer) - _BaseContainer->detachContainer(_Peoples[index].Container); + CGroupContainer *parentContainer = _Peoples[index].Container->getProprietaryContainer(); + if (parentContainer) + parentContainer->detachContainer(_Peoples[index].Container); } CInterfaceManager *im = CInterfaceManager::getInstance(); CInterfaceGroup *pRoot = dynamic_cast(CWidgetManager::getInstance()->getElementFromId("ui:interface")); @@ -447,6 +483,150 @@ void CPeopleList::setContactId(uint index, uint32 contactId) _Peoples[index].ContactId = contactId; } +//================================================================== +void CPeopleList::changeGroup(uint index, const ucstring &groupName) +{ + if (index >= _Peoples.size()) + { + nlwarning(" bad index."); + return; + } + ucstring group = groupName; + if (group.toString() == "General") + group = ucstring(""); + _Peoples[index].Group = group; + + for (uint k = 0; k < _GroupContainers.size(); ++k) + { + if (_GroupContainers[k].first == group.toString()) + return; + } + + vector > properties; + properties.push_back(make_pair(string("posparent"), string("parent"))); + properties.push_back(make_pair(string("id"), _ContainerID + "_group_" + toString(_GroupContainers.size()))); + if (group.toString() == "") + properties.push_back(make_pair(string("title"), "General")); + else + properties.push_back(make_pair(string("title"), group.toString())); + CGroupContainer *gc = dynamic_cast(CWidgetManager::getInstance()->getParser()->createGroupInstance("people_list_group_header", "ui:interface", properties, false)); + + if (group.toString() == "") + gc->setUCTitle(ucstring("General")); + else + gc->setUCTitle(group.toString()); + gc->setSavable(false); + + CInterfaceGroup *pRoot = dynamic_cast(CWidgetManager::getInstance()->getElementFromId("ui:interface")); + pRoot->addGroup (gc); + _BaseContainer->attachContainer(gc); + + _GroupContainers.push_back(make_pair(group.toString(), gc)); + + std::sort(_GroupContainers.begin(), _GroupContainers.end()); +} + +//================================================================== +void CPeopleList::readContactGroups() +{ + _GroupContainers.clear(); + const std::string filename = CInterfaceManager::getInstance()->getSaveFileName("contactgroups", "xml"); + try + { + CIFile fd; + if (fd.open(CPath::lookup(filename))) + { + CIXml stream; + stream.init(fd); + + xmlKeepBlanksDefault(0); + xmlNodePtr root = stream.getRootNode(); + + if (!root) return; + + xmlNodePtr node = root->children; + uint nb = 0; + while (node) + { + CXMLAutoPtr propName = xmlGetProp(node, (xmlChar*)"name"); + CXMLAutoPtr propGroup = xmlGetProp(node, (xmlChar*)"group"); + if (propName && propGroup) + { + sint index = getIndexFromName(propName.str()); + if (index < _Peoples.size()) + { + _Peoples[index].Group = propGroup.str(); + if (_GroupContainers.empty() || _GroupContainers.back().first != propName.str()) { + vector > properties; + properties.push_back(make_pair(string("posparent"), string("parent"))); + properties.push_back(make_pair(string("id"), _ContainerID + "_group_" + toString(_GroupContainers.size()))); + if (propGroup.str() == "") + properties.push_back(make_pair(string("title"), "General")); + else + properties.push_back(make_pair(string("title"), propGroup.str())); + CInterfaceGroup *group = CWidgetManager::getInstance()->getParser()->createGroupInstance("people_list_group_header", "ui:interface", properties, false); + CGroupContainer *gc = dynamic_cast(group); + if (propGroup.str() == "") + gc->setUCTitle(ucstring("General")); + else + gc->setUCTitle(propGroup.str()); + gc->setSavable(false); + + CInterfaceGroup *pRoot = dynamic_cast(CWidgetManager::getInstance()->getElementFromId("ui:interface")); + pRoot->addGroup (gc); + _BaseContainer->attachContainer(gc); + + _GroupContainers.push_back(make_pair(propGroup.str(), gc)); + } + } + } + node = node->next; + nb++; + } + fd.close(); + } + std::sort(_GroupContainers.begin(), _GroupContainers.end()); + } + catch (const Exception &e) + { + nlwarning("Error while parsing xml file %s : %s", filename.c_str(), e.what()); + } +} + +//================================================================== +void CPeopleList::saveContactGroups() +{ + const std::string filename = CInterfaceManager::getInstance()->getSaveFileName("contactgroups", "xml"); + try + { + COFile fd; + if (fd.open(filename, false, false, true)) + { + COXml stream; + stream.init(&fd); + + xmlDocPtr doc = stream.getDocument(); + xmlNodePtr node = xmlNewDocNode(doc, NULL, (const xmlChar*)"contact_groups", NULL); + xmlDocSetRootElement(doc, node); + + for (uint k = 0; k < _Peoples.size(); ++k) + { + xmlNodePtr newNode = xmlNewChild(node, NULL, (const xmlChar*)"contact", NULL); + + xmlSetProp(newNode, (const xmlChar*)"name", (const xmlChar*)_Peoples[k].getName().toString().c_str()); + xmlSetProp(newNode, (const xmlChar*)"group", (const xmlChar*)_Peoples[k].Group.toString().c_str()); + } + stream.flush(); + fd.close(); + } + nlinfo("save %s", filename.c_str()); + } + catch (const Exception &e) + { + nlwarning("Error while writing the file %s : %s", filename.c_str(), e.what()); + } +} + //================================================================== void CPeopleList::displayLocalPlayerTell(const ucstring &receiver, uint index, const ucstring &msg,uint numBlinks /*=0*/) { @@ -617,12 +797,12 @@ void CPeopleList::setPeopleMenu(const std::string &menuName) } void CPeopleList::setPeopleMenuEx(const std::string &offlineUnblockedMenuName, - const std::string &onlineUnblockedMenuName, - const std::string &onlineAbroadUnblockedMenuName, - const std::string &offlineBockedMenuName, - const std::string &onlineBlockedMenuName, - const std::string &onlineAbroadBlockedMenuName - ) + const std::string &onlineUnblockedMenuName, + const std::string &onlineAbroadUnblockedMenuName, + const std::string &offlineBockedMenuName, + const std::string &onlineBlockedMenuName, + const std::string &onlineAbroadBlockedMenuName + ) { _PeopleMenuOfflineUnblocked = offlineUnblockedMenuName; _PeopleMenuOnlineUnblocked = onlineUnblockedMenuName; diff --git a/code/ryzom/client/src/interface_v3/people_list.h b/code/ryzom/client/src/interface_v3/people_list.h index 6845ce73a..682b1a6e5 100644 --- a/code/ryzom/client/src/interface_v3/people_list.h +++ b/code/ryzom/client/src/interface_v3/people_list.h @@ -110,6 +110,11 @@ public: void setContactId(uint index, uint32 contactId); sint getIndexFromContactId(uint32 contactId); + // For Friend Groups management + void changeGroup(uint index, const ucstring &groupName); + void readContactGroups(); + void saveContactGroups(); + /** Display a message for the given people * If the window is closed, it causes it to blink (and also the parent window) */ @@ -165,6 +170,7 @@ private: typedef std::vector TPeopleVect; private: CGroupContainerPtr _BaseContainer; + std::vector > > _GroupContainers; NLMISC::CRefPtr _ChatWindow; TPeopleVect _Peoples; CPeopleListDesc::TContactType _ContactType; From f96f0b41b9de2afcc335478d04463a51e23d4190 Mon Sep 17 00:00:00 2001 From: Sit Melai Date: Tue, 1 Sep 2020 18:41:45 +0200 Subject: [PATCH 3/5] Removed an unused variable and don't show groups anymore when there is only one --- code/ryzom/client/src/interface_v3/people_list.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/code/ryzom/client/src/interface_v3/people_list.cpp b/code/ryzom/client/src/interface_v3/people_list.cpp index ece5b5cc8..33d1c900e 100644 --- a/code/ryzom/client/src/interface_v3/people_list.cpp +++ b/code/ryzom/client/src/interface_v3/people_list.cpp @@ -281,9 +281,8 @@ void CPeopleList::sortEx(TSortOrder order) } CGroupContainer *group = _BaseContainer; - ucstring groupName = ""; uint groupIndex = 0; - + for(k = 0; k < _Peoples.size(); ++k) { bool newGroup = false; @@ -296,10 +295,9 @@ void CPeopleList::sortEx(TSortOrder order) newGroup = true; ++groupIndex; } - if (newGroup && groupIndex < _GroupContainers.size()) + if (newGroup && groupIndex < _GroupContainers.size() && _GroupContainers.size() > 1) { group = _GroupContainers[groupIndex].second; - groupName = _GroupContainers[groupIndex].first; _BaseContainer->attachContainer(group); } group->attachContainer(_Peoples[k].Container); @@ -556,7 +554,7 @@ void CPeopleList::readContactGroups() if (index < _Peoples.size()) { _Peoples[index].Group = propGroup.str(); - if (_GroupContainers.empty() || _GroupContainers.back().first != propName.str()) { + if (_GroupContainers.empty() || _GroupContainers.back().first != propGroup.str()) { vector > properties; properties.push_back(make_pair(string("posparent"), string("parent"))); properties.push_back(make_pair(string("id"), _ContainerID + "_group_" + toString(_GroupContainers.size()))); From 02732c124141d54a100a000ddb31772a2a93019e Mon Sep 17 00:00:00 2001 From: Sit Melai Date: Thu, 3 Sep 2020 13:14:50 +0200 Subject: [PATCH 4/5] Changes to fix compilation on some setups --- code/ryzom/client/src/interface_v3/people_list.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/ryzom/client/src/interface_v3/people_list.cpp b/code/ryzom/client/src/interface_v3/people_list.cpp index 33d1c900e..47806bf5f 100644 --- a/code/ryzom/client/src/interface_v3/people_list.cpp +++ b/code/ryzom/client/src/interface_v3/people_list.cpp @@ -546,8 +546,10 @@ void CPeopleList::readContactGroups() uint nb = 0; while (node) { - CXMLAutoPtr propName = xmlGetProp(node, (xmlChar*)"name"); - CXMLAutoPtr propGroup = xmlGetProp(node, (xmlChar*)"group"); + CXMLAutoPtr propName; + propName = (char*) xmlGetProp(node, (xmlChar*)"name"); + CXMLAutoPtr propGroup; + propGroup = (char*) xmlGetProp(node, (xmlChar*)"group"); if (propName && propGroup) { sint index = getIndexFromName(propName.str()); From 47bf9ecbc8e2eeb8cc4ce5787cfa3ec8c103f044 Mon Sep 17 00:00:00 2001 From: Sit Melai Date: Thu, 3 Sep 2020 21:12:10 +0200 Subject: [PATCH 5/5] Always create General group, so at first launch groups show directly when changed --- .../client/src/interface_v3/people_list.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/code/ryzom/client/src/interface_v3/people_list.cpp b/code/ryzom/client/src/interface_v3/people_list.cpp index 47806bf5f..c3f2cf4d7 100644 --- a/code/ryzom/client/src/interface_v3/people_list.cpp +++ b/code/ryzom/client/src/interface_v3/people_list.cpp @@ -528,6 +528,23 @@ void CPeopleList::changeGroup(uint index, const ucstring &groupName) void CPeopleList::readContactGroups() { _GroupContainers.clear(); + + // Create default group even if no groups defined + vector > properties; + properties.push_back(make_pair(string("posparent"), string("parent"))); + properties.push_back(make_pair(string("id"), _ContainerID + "_group_0")); + properties.push_back(make_pair(string("title"), "General")); + CInterfaceGroup *group = CWidgetManager::getInstance()->getParser()->createGroupInstance("people_list_group_header", "ui:interface", properties, false); + CGroupContainer *gc = dynamic_cast(group); + gc->setUCTitle(ucstring("General")); + gc->setSavable(false); + + CInterfaceGroup *pRoot = dynamic_cast(CWidgetManager::getInstance()->getElementFromId("ui:interface")); + pRoot->addGroup (gc); + _BaseContainer->attachContainer(gc); + + _GroupContainers.push_back(make_pair("", gc)); + const std::string filename = CInterfaceManager::getInstance()->getSaveFileName("contactgroups", "xml"); try {