#include "pch.h"
#include "trekctrls.h"
#include "trekmdl.h"
#include "badwords.h"
class ChatListItem : public ListItem
{
private:
long m_lData;
ChatInfo* m_pchatInfo;
TVector<ZString> m_vMsgLines;
WinPoint m_ptLineSize;
public:
ChatListItem(ChatInfo* pchatInfo, const WinPoint& ptLineSize) :
m_lData((long)pchatInfo),
m_pchatInfo(pchatInfo),
m_ptLineSize(ptLineSize)
{
ZString strMsg = CensorBadWords (m_pchatInfo->GetMessage());
IEngineFont* pfont = pchatInfo->IsFromLeader() ? TrekResources::SmallBoldFont() : TrekResources::SmallFont();
int nStrLenLeft = strMsg.GetLength();
int nStrLenLine;
while ((nStrLenLine = pfont->GetMaxTextLength(strMsg, ptLineSize.X(), true))
< nStrLenLeft)
{
int nStrLenWordBreak = nStrLenLine;
while (nStrLenWordBreak > 2 && strMsg[nStrLenWordBreak] != ' ' && strMsg[nStrLenWordBreak-1] != ' ')
nStrLenWordBreak--;
if (nStrLenWordBreak != 2)
nStrLenLine = nStrLenWordBreak;
if (nStrLenLine <= 2)
{
nStrLenLine = 3;
m_vMsgLines.PushEnd("");
}
else
{
m_vMsgLines.PushEnd(strMsg.Left(nStrLenLine));
}
strMsg = " " + strMsg.RightOf(nStrLenLine);
nStrLenLeft -= nStrLenLine - 2;
ZAssert(strMsg.GetLength() == nStrLenLeft);
}
m_vMsgLines.PushEnd(strMsg);
}
~ChatListItem()
{
}
short GetItemHeight()
{
return m_vMsgLines.GetCount();
}
long GetItemData()
{
return m_lData;
};
bool Update()
{
return true;
}
void SetSortOrder(long lSortOrder)
{
}
bool SetFilter(long lFilter)
{
return true;
}
void DrawItem(Surface* pSurface, const WinRect& rect, bool fSelected, int iFirstSlot)
{
IEngineFont* pfont = m_pchatInfo->IsFromLeader() ? TrekResources::SmallBoldFont() : TrekResources::SmallFont();
WinPoint pt(rect.Min() + WinPoint(3,3));
for (
int i = iFirstSlot;
i < m_vMsgLines.GetCount() && pt.Y() < rect.YMax();
i++
) {
pSurface->DrawString(pfont, m_pchatInfo->GetColor(), pt, m_vMsgLines[i]);
pt += WinPoint(0, m_ptLineSize.Y());
}
}
};
class ChatListPaneImpl : public ChatListPane,
public EventTargetContainer<ChatListPaneImpl>,
public TrekClientEventSink,
public IKeyboardInput
{
private:
TRef<ListPaneOld> m_pListPane;
WinPoint m_ptItemSize;
TList<ChatTarget> m_listChannels;
TRef<IKeyboardInput> m_keyboardDelegate;
TRef<IEventTarget> m_targetAutoscrollOn;
bool m_bAutoscroll;
bool m_bPlayerChatsOnly;
bool m_bIgnoreScrollingEvents;
public:
ChatListPaneImpl(const WinPoint& ptSize):
m_ptItemSize(ptSize.X(), 12), m_bAutoscroll(true), m_bIgnoreScrollingEvents(false)
{
m_bPlayerChatsOnly = true;
m_pListPane = ListPaneOld::Create(ptSize, 12, true, NULL),
InsertAtBottom(m_pListPane);
AddEventTarget(&ChatListPaneImpl::OnListSelect, m_pListPane->GetEventSource());
AddEventTarget(&ChatListPaneImpl::OnScroll, m_pListPane->GetScrollEvent());
UpdateContents();
m_keyboardDelegate = IKeyboardInput::CreateDelegate(this);
GetWindow()->AddKeyboardInputFilter(m_keyboardDelegate);
}
~ChatListPaneImpl()
{
GetWindow()->RemoveKeyboardInputFilter(m_keyboardDelegate);
if (m_targetAutoscrollOn)
m_targetAutoscrollOn->Disconnect();
}
void AutoscrollOff()
{
m_bAutoscroll = false;
if (m_targetAutoscrollOn)
m_targetAutoscrollOn->Disconnect();
m_targetAutoscrollOn =
new TEventTarget<ChatListPaneImpl>(this, &ChatListPaneImpl::OnAutoscrollTimeout, GetWindow(), 10);
}
void AutoscrollOn()
{
m_bAutoscroll = true;
if (m_targetAutoscrollOn)
m_targetAutoscrollOn->Disconnect();
}
bool OnAutoscrollTimeout()
{
m_pListPane->ScrollBottom();
AutoscrollOn();
return false;
}
bool OnListSelect(int nSel)
{
return true;
}
void OnClearChat()
{
m_pListPane->RemoveAll();
}
void OnChatMessageChange()
{
int countOld = m_pListPane->GetCountItems();
int posOld = m_pListPane->GetScrollPosition();
UpdateContents();
if (countOld == m_pListPane->GetCountItems())
m_pListPane->SetScrollPosition(posOld);
}
bool ChatIsNonCriticalMessage(ChatInfo * pchatinfo)
{
return !pchatinfo->IsFromPlayer()
&& !pchatinfo->IsFromObjectModel()
&& pchatinfo->GetChatTarget() != CHAT_INDIVIDUAL_NOFILTER
&& m_bPlayerChatsOnly;
}
void OnDeleteChatMessage(ChatInfo* pchatInfo)
{
m_bIgnoreScrollingEvents = true;
m_pListPane->RemoveItemByData((long)pchatInfo);
m_bIgnoreScrollingEvents = false;
}
void OnNewChatMessage()
{
ChatInfo * pchatinfo = &(trekClient.m_chatList.last()->data());
if (ChatIsNonCriticalMessage(pchatinfo))
{
trekClient.PostText(false, CensorBadWords (pchatinfo->GetMessage()));
}
else
{
AddChatItem(pchatinfo);
}
}
void PageUp()
{
m_pListPane->ScrollPageUp();
AutoscrollOff();
}
void PageDown()
{
m_pListPane->ScrollPageDown();
if (m_pListPane->IsItemVisibleByIdx(m_pListPane->GetCountItems() - 1))
AutoscrollOn();
else
AutoscrollOff();
}
bool OnScroll()
{
if (!m_bIgnoreScrollingEvents)
{
if (m_pListPane->IsItemVisibleByIdx(m_pListPane->GetCountItems() - 1))
AutoscrollOn();
else
AutoscrollOff();
}
return true;
}
void UpdateContents()
{
m_pListPane->RemoveAll();
for (ChatLink* link = trekClient.m_chatList.first(); link; link = link->next())
{
AddChatItem(&(link->data()));
}
m_pListPane->ScrollBottom();
AutoscrollOn();
}
bool ChatPassesFilter(ChatInfo* pchatInfo)
{
if (ChatIsNonCriticalMessage(pchatInfo))
{
return false;
}
if (m_listChannels.IsEmpty())
{
return true;
}
else
{
TList<ChatTarget>::Iterator iter(m_listChannels);
while (!iter.End())
{
if (iter.Value() == pchatInfo->GetChatTarget())
return true;
iter.Next();
}
}
return false;
}
void AddChatItem(ChatInfo* pchatInfo)
{
if (ChatPassesFilter(pchatInfo))
{
m_bIgnoreScrollingEvents = true;
int idx = m_pListPane->AppendItem(new ChatListItem(pchatInfo, m_ptItemSize));
if (m_bAutoscroll)
{
m_pListPane->SetSelItemByIdx(idx);
m_pListPane->ScrollBottom();
}
m_bIgnoreScrollingEvents = false;
}
}
void AddChannel(ChatTarget channel)
{
m_listChannels.PushEnd(channel);
UpdateContents();
}
void RemoveChannel(ChatTarget channel)
{
m_listChannels.Remove(channel);
UpdateContents();
}
void ResetChannels()
{
m_listChannels.SetEmpty();
UpdateContents();
}
void UpdateLayout()
{
DefaultUpdateLayout();
}
};
TRef<IObject> ChatListPaneFactory::Apply(ObjectStack& stack)
{
TRef<PointValue> ppointSize; CastTo(ppointSize, stack.Pop());
return (Pane*)new ChatListPaneImpl(
WinPoint(
(int)ppointSize->GetValue().X(),
(int)ppointSize->GetValue().Y()
)
);
}