/* * OpenClonk, http://www.openclonk.org * * Copyright (c) 2007-2009, RedWolf Design GmbH, http://www.clonk.de/ * Copyright (c) 2013-2016, The OpenClonk Team and contributors * * Distributed under the terms of the ISC license; see accompanying file * "COPYING" for details. * * "Clonk" is a registered trademark of Matthes Bender, used with permission. * See accompanying file "TRADEMARK" for details. * * To redistribute this file separately, substitute the full license texts * for the above references. */ // IRC client dialog #ifndef INC_C4ChatDlg #define INC_C4ChatDlg #include "gui/C4Gui.h" #include "network/C4InteractiveThread.h" // a GUI control to chat in class C4ChatControl : public C4GUI::Window, private C4InteractiveThread::Callback { private: // one open channel or query class ChatSheet : public C4GUI::Tabular::Sheet { public: // one item in the nick list class NickItem : public C4GUI::Window { private: C4GUI::Icon *pStatusIcon; // status icon indicating channel status (e.g. operator) C4GUI::Label *pNameLabel; // the nickname bool fFlaggedExisting; // flagged for existance; used by user update func int32_t iStatus; public: NickItem(class C4Network2IRCUser *pByUser); protected: void UpdateOwnPos() override; public: const char *GetNick() const { return pNameLabel->GetText(); } int32_t GetStatus() const { return iStatus; } void Update(class C4Network2IRCUser *pByUser); void SetFlaggedExisting(bool fToVal) { fFlaggedExisting = fToVal; } bool IsFlaggedExisting() const { return fFlaggedExisting; } static int32_t SortFunc(const C4GUI::Element *pEl1, const C4GUI::Element *pEl2, void *); }; enum SheetType { CS_Server, CS_Channel, CS_Query }; private: C4ChatControl *pChatControl; C4GUI::TextWindow *pChatBox; C4GUI::ListBox *pNickList; C4GUI::WoodenLabel *pInputLbl; C4GUI::Edit *pInputEdit; int32_t iBackBufferIndex; // chat message history index SheetType eType; StdStrBuf sIdent; bool fHasUnread; StdStrBuf sChatTitle; // topic for channels; name+ident for queries; server name for server sheet C4KeyBinding *pKeyHistoryUp, *pKeyHistoryDown; // keys used to scroll through chat history public: ChatSheet(C4ChatControl *pChatControl, const char *szTitle, const char *szIdent, SheetType eType); ~ChatSheet() override; C4GUI::Edit *GetInputEdit() const { return pInputEdit; } SheetType GetSheetType() const { return eType; } const char *GetIdent() const { return sIdent.getData(); } void SetIdent(const char *szToIdent) { sIdent.Copy(szToIdent); } const char *GetChatTitle() const { return sChatTitle.getData(); } void SetChatTitle(const char *szNewTitle) { sChatTitle.Copy(szNewTitle); } void AddTextLine(const char *szText, uint32_t dwClr); void DoError(const char *szError); void Update(bool fLock); void UpdateUsers(C4Network2IRCUser *pUsers); void ResetUnread(); // mark messages as read protected: void UpdateSize() override; void OnShown(bool fByUser) override; void UserClose() override; // user pressed close button: Close queries, part channels, etc. C4GUI::Edit::InputResult OnChatInput(C4GUI::Edit *edt, bool fPasting, bool fPastingMore); bool KeyHistoryUpDown(bool fUp); void OnNickDblClick(class C4GUI::Element *pEl); private: NickItem *GetNickItem(const char *szByNick); NickItem *GetFirstNickItem() { return pNickList ? static_cast(pNickList->GetFirst()) : nullptr; } NickItem *GetNextNickItem(NickItem *pPrev) { return static_cast(pPrev->GetNext()); } }; private: C4GUI::Tabular *pTabMain, *pTabChats; // login controls C4GUI::Label *pLblLoginNick, *pLblLoginPass, *pLblLoginRealName, *pLblLoginChannel; C4GUI::Edit *pEdtLoginNick, *pEdtLoginPass, *pEdtLoginRealName, *pEdtLoginChannel; C4GUI::Button *pBtnLogin; StdStrBuf sTitle; C4GUI::BaseInputCallback *pTitleChangeBC; C4Network2IRCClient *pIRCClient; bool fInitialMessagesReceived; // set after initial update call, which fetches all messages. Subsequent calls fetch only unread messages public: C4ChatControl(C4Network2IRCClient *pIRC); ~C4ChatControl() override; protected: void UpdateSize() override; C4GUI::Edit::InputResult OnLoginDataEnter(C4GUI::Edit *edt, bool fPasting, bool fPastingMore); // advance focus when user presses enter in one of the login edits void OnConnectBtn(C4GUI::Control *btn); // callback: connect button pressed public: virtual class C4GUI::Control *GetDefaultControl(); C4Network2IRCClient *getIRCClient() { return pIRCClient; } void SetTitleChangeCB(C4GUI::BaseInputCallback *pNewCB); virtual void OnShown(); // callback when shown void UpdateShownPage(); void Update(); void UpdateTitle(); bool DlgEnter(); void OnSec1Timer() { Update(); } // timer proc bool ProcessInput(const char *szInput, ChatSheet *pChatSheet); // process chat input - return false if no more pasting is to be done (i.e., on /quit or /part in channel) const char *GetTitle() { return sTitle.getData(); } void UserQueryQuit(); ChatSheet *OpenQuery(const char *szForNick, bool fSelect, const char *szIdentFallback); private: static bool IsServiceName(const char *szName); ChatSheet *GetActiveChatSheet(); ChatSheet *GetSheetByTitle(const char *szTitle, C4ChatControl::ChatSheet::SheetType eType); ChatSheet *GetSheetByIdent(const char *szIdent, C4ChatControl::ChatSheet::SheetType eType); ChatSheet *GetServerSheet(); void ClearChatSheets(); // IRC event hook void OnThreadEvent(C4InteractiveEventType eEvent, void *pEventData) override { if (pEventData == pIRCClient) Update(); } }; // container dialog for the C4ChatControl class C4ChatDlg : public C4GUI::Dialog { private: static C4ChatDlg *pInstance; class C4ChatControl *pChatCtrl; C4GUI::Button *pBtnClose; public: C4ChatDlg(); ~C4ChatDlg() override; static C4ChatDlg *ShowChat(); static void StopChat(); static bool IsChatActive(); static bool IsChatEnabled(); static bool ToggleChat(); protected: // default control to be set if unprocessed keyboard input has been detected class C4GUI::Control *GetDefaultControl() override; // true for dialogs that should span the whole screen // not just the mouse-viewport bool IsFreePlaceDialog() override { return true; } // true for dialogs that receive keyboard input even in shared mode bool IsExclusiveDialog() override { return true; } // for custom placement procedures; should call SetPos bool DoPlacement(C4GUI::Screen *pOnScreen, const C4Rect &rPreferredDlgRect) override; void OnClosed(bool fOK) override; // callback when dlg got closed void OnShown() override; // callback when shown - should not delete the dialog void UpdateSize() override; void OnExitBtn(C4GUI::Control *btn); // callback: exit button pressed void OnChatTitleChange(const StdStrBuf &sNewTitle); }; #endif // INC_C4ChatDlg