chatpane.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. #include "pch.h"
  2. #include "trekctrls.h"
  3. #include "trekmdl.h"
  4. #include "badwords.h"
  5. //////////////////////////////////////////////////////////////////////////////
  6. //
  7. // ChatListItem
  8. //
  9. //////////////////////////////////////////////////////////////////////////////
  10. class ChatListItem : public ListItem
  11. {
  12. private:
  13. long m_lData;
  14. ChatInfo* m_pchatInfo;
  15. TVector<ZString> m_vMsgLines;
  16. WinPoint m_ptLineSize;
  17. public:
  18. ChatListItem(ChatInfo* pchatInfo, const WinPoint& ptLineSize) :
  19. m_lData((long)pchatInfo),
  20. m_pchatInfo(pchatInfo),
  21. m_ptLineSize(ptLineSize)
  22. {
  23. ZString strMsg = CensorBadWords (m_pchatInfo->GetMessage());
  24. IEngineFont* pfont = pchatInfo->IsFromLeader() ? TrekResources::SmallBoldFont() : TrekResources::SmallFont();
  25. int nStrLenLeft = strMsg.GetLength();
  26. int nStrLenLine;
  27. while ((nStrLenLine = pfont->GetMaxTextLength(strMsg, ptLineSize.X(), true))
  28. < nStrLenLeft)
  29. {
  30. int nStrLenWordBreak = nStrLenLine;
  31. while (nStrLenWordBreak > 2 && strMsg[nStrLenWordBreak] != ' ' && strMsg[nStrLenWordBreak-1] != ' ')
  32. nStrLenWordBreak--;
  33. if (nStrLenWordBreak != 2)
  34. nStrLenLine = nStrLenWordBreak;
  35. if (nStrLenLine <= 2)
  36. {
  37. // put a blank line without the character
  38. nStrLenLine = 3;
  39. m_vMsgLines.PushEnd("");
  40. }
  41. else
  42. {
  43. m_vMsgLines.PushEnd(strMsg.Left(nStrLenLine));
  44. }
  45. strMsg = " " + strMsg.RightOf(nStrLenLine);
  46. nStrLenLeft -= nStrLenLine - 2;
  47. ZAssert(strMsg.GetLength() == nStrLenLeft);
  48. }
  49. m_vMsgLines.PushEnd(strMsg);
  50. }
  51. ~ChatListItem()
  52. {
  53. // debugf("~ChatListItem\n");
  54. }
  55. short GetItemHeight()
  56. {
  57. return m_vMsgLines.GetCount();
  58. }
  59. long GetItemData()
  60. {
  61. return m_lData;
  62. };
  63. bool Update()
  64. {
  65. return true;
  66. }
  67. void SetSortOrder(long lSortOrder)
  68. {
  69. }
  70. bool SetFilter(long lFilter)
  71. {
  72. return true;
  73. }
  74. void DrawItem(Surface* pSurface, const WinRect& rect, bool fSelected, int iFirstSlot)
  75. {
  76. IEngineFont* pfont = m_pchatInfo->IsFromLeader() ? TrekResources::SmallBoldFont() : TrekResources::SmallFont();
  77. WinPoint pt(rect.Min() + WinPoint(3,3));
  78. for (
  79. int i = iFirstSlot;
  80. i < m_vMsgLines.GetCount() && pt.Y() < rect.YMax();
  81. i++
  82. ) {
  83. pSurface->DrawString(pfont, m_pchatInfo->GetColor(), pt, m_vMsgLines[i]);
  84. pt += WinPoint(0, m_ptLineSize.Y());
  85. }
  86. }
  87. };
  88. //////////////////////////////////////////////////////////////////////////////
  89. //
  90. // ChatListPaneImpl
  91. //
  92. //////////////////////////////////////////////////////////////////////////////
  93. class ChatListPaneImpl : public ChatListPane,
  94. public EventTargetContainer<ChatListPaneImpl>,
  95. public TrekClientEventSink,
  96. public IKeyboardInput
  97. {
  98. private:
  99. TRef<ListPaneOld> m_pListPane;
  100. WinPoint m_ptItemSize;
  101. TList<ChatTarget> m_listChannels;
  102. TRef<IKeyboardInput> m_keyboardDelegate;
  103. TRef<IEventTarget> m_targetAutoscrollOn;
  104. bool m_bAutoscroll;
  105. bool m_bPlayerChatsOnly;
  106. bool m_bIgnoreScrollingEvents;
  107. public:
  108. ChatListPaneImpl(const WinPoint& ptSize):
  109. m_ptItemSize(ptSize.X(), 12), m_bAutoscroll(true), m_bIgnoreScrollingEvents(false)
  110. {
  111. m_bPlayerChatsOnly = true;
  112. m_pListPane = ListPaneOld::Create(ptSize, 12, true, NULL),
  113. InsertAtBottom(m_pListPane);
  114. AddEventTarget(OnListSelect, m_pListPane->GetEventSource());
  115. AddEventTarget(OnScroll, m_pListPane->GetScrollEvent());
  116. UpdateContents();
  117. m_keyboardDelegate = IKeyboardInput::CreateDelegate(this);
  118. GetWindow()->AddKeyboardInputFilter(m_keyboardDelegate);
  119. }
  120. ~ChatListPaneImpl()
  121. {
  122. GetWindow()->RemoveKeyboardInputFilter(m_keyboardDelegate);
  123. if (m_targetAutoscrollOn)
  124. m_targetAutoscrollOn->Disconnect();
  125. }
  126. void AutoscrollOff()
  127. {
  128. m_bAutoscroll = false;
  129. // set/reset a timer to turn it back on after 10 seconds
  130. if (m_targetAutoscrollOn)
  131. m_targetAutoscrollOn->Disconnect();
  132. m_targetAutoscrollOn =
  133. new TEventTarget<ChatListPaneImpl>(this, OnAutoscrollTimeout, GetWindow(), 10);
  134. }
  135. void AutoscrollOn()
  136. {
  137. m_bAutoscroll = true;
  138. if (m_targetAutoscrollOn)
  139. m_targetAutoscrollOn->Disconnect();
  140. }
  141. bool OnAutoscrollTimeout()
  142. {
  143. m_pListPane->ScrollBottom();
  144. AutoscrollOn();
  145. return false;
  146. }
  147. bool OnListSelect(int nSel)
  148. {
  149. return true;
  150. }
  151. void OnClearChat()
  152. {
  153. m_pListPane->RemoveAll();
  154. }
  155. void OnChatMessageChange()
  156. {
  157. // save some info about the current state of the chat list
  158. int countOld = m_pListPane->GetCountItems();
  159. int posOld = m_pListPane->GetScrollPosition();
  160. UpdateContents();
  161. // if the number of items did not change, assume we were just doing
  162. // something like marking a player as dead so keep the current scroll
  163. // position.
  164. if (countOld == m_pListPane->GetCountItems())
  165. m_pListPane->SetScrollPosition(posOld);
  166. }
  167. bool ChatIsNonCriticalMessage(ChatInfo * pchatinfo)
  168. {
  169. return !pchatinfo->IsFromPlayer()
  170. && !pchatinfo->IsFromObjectModel()
  171. && pchatinfo->GetChatTarget() != CHAT_INDIVIDUAL_NOFILTER
  172. && m_bPlayerChatsOnly;
  173. }
  174. void OnDeleteChatMessage(ChatInfo* pchatInfo)
  175. {
  176. m_bIgnoreScrollingEvents = true;
  177. m_pListPane->RemoveItemByData((long)pchatInfo);
  178. m_bIgnoreScrollingEvents = false;
  179. }
  180. void OnNewChatMessage()
  181. {
  182. ChatInfo * pchatinfo = &(trekClient.m_chatList.last()->data());
  183. if (ChatIsNonCriticalMessage(pchatinfo))
  184. {
  185. trekClient.PostText(false, CensorBadWords (pchatinfo->GetMessage()));
  186. }
  187. else
  188. {
  189. AddChatItem(pchatinfo);
  190. }
  191. }
  192. void PageUp()
  193. {
  194. m_pListPane->ScrollPageUp();
  195. AutoscrollOff();
  196. }
  197. void PageDown()
  198. {
  199. m_pListPane->ScrollPageDown();
  200. // if we are at the bottom of the list, turn auto-scroll back on
  201. if (m_pListPane->IsItemVisibleByIdx(m_pListPane->GetCountItems() - 1))
  202. AutoscrollOn();
  203. else
  204. AutoscrollOff();
  205. }
  206. bool OnScroll()
  207. {
  208. if (!m_bIgnoreScrollingEvents)
  209. {
  210. // if we are at the bottom of the list, turn auto-scroll back on
  211. if (m_pListPane->IsItemVisibleByIdx(m_pListPane->GetCountItems() - 1))
  212. AutoscrollOn();
  213. else
  214. AutoscrollOff();
  215. }
  216. return true;
  217. }
  218. void UpdateContents()
  219. {
  220. m_pListPane->RemoveAll();
  221. for (ChatLink* link = trekClient.m_chatList.first(); link; link = link->next())
  222. {
  223. AddChatItem(&(link->data()));
  224. }
  225. m_pListPane->ScrollBottom();
  226. AutoscrollOn();
  227. }
  228. bool ChatPassesFilter(ChatInfo* pchatInfo)
  229. {
  230. if (ChatIsNonCriticalMessage(pchatInfo))
  231. {
  232. return false;
  233. }
  234. if (m_listChannels.IsEmpty())
  235. {
  236. return true;
  237. }
  238. else
  239. {
  240. TList<ChatTarget>::Iterator iter(m_listChannels);
  241. while (!iter.End())
  242. {
  243. if (iter.Value() == pchatInfo->GetChatTarget())
  244. return true;
  245. iter.Next();
  246. }
  247. }
  248. return false;
  249. }
  250. void AddChatItem(ChatInfo* pchatInfo)
  251. {
  252. if (ChatPassesFilter(pchatInfo))
  253. {
  254. m_bIgnoreScrollingEvents = true;
  255. int idx = m_pListPane->AppendItem(new ChatListItem(pchatInfo, m_ptItemSize));
  256. if (m_bAutoscroll)
  257. {
  258. m_pListPane->SetSelItemByIdx(idx);
  259. m_pListPane->ScrollBottom();
  260. }
  261. m_bIgnoreScrollingEvents = false;
  262. }
  263. }
  264. void AddChannel(ChatTarget channel)
  265. {
  266. m_listChannels.PushEnd(channel);
  267. UpdateContents();
  268. }
  269. void RemoveChannel(ChatTarget channel)
  270. {
  271. m_listChannels.Remove(channel);
  272. UpdateContents();
  273. }
  274. void ResetChannels()
  275. {
  276. m_listChannels.SetEmpty();
  277. UpdateContents();
  278. }
  279. void UpdateLayout()
  280. {
  281. DefaultUpdateLayout();
  282. }
  283. };
  284. TRef<IObject> ChatListPaneFactory::Apply(ObjectStack& stack)
  285. {
  286. TRef<PointValue> ppointSize; CastTo(ppointSize, stack.Pop());
  287. return (Pane*)new ChatListPaneImpl(
  288. WinPoint(
  289. (int)ppointSize->GetValue().X(),
  290. (int)ppointSize->GetValue().Y()
  291. )
  292. );
  293. }