#include "stdafx.h" #include "CChatScreen.h" #include "CConfig.h" #include "CAppletManager.h" //************************************************************************ // Constructor //************************************************************************ CChatScreen::CChatScreen() { } //************************************************************************ // Destructor //************************************************************************ CChatScreen::~CChatScreen() { } //************************************************************************ // Initializes the screen //************************************************************************ bool CChatScreen::Initialize() { if (!CScreen::Initialize()) return false; m_InfoText.Initialize(); m_UserName.Initialize(); m_UserStatus.Initialize(); m_UserProto.Initialize(); m_Input.Initialize(); m_TextLog.Initialize(); m_Scrollbar.Initialize(); UpdateObjects(); // other attributes m_InfoText.SetAlignment(DT_CENTER); m_InfoText.SetWordWrap(TRUE); m_InfoText.SetText(L""); m_InfoText.Show(0); m_UserName.SetAlignment(DT_CENTER); m_UserName.SetWordWrap(TRUE); m_UserName.SetText(L"Proto"); m_UserStatus.SetAlignment(DT_LEFT); m_UserStatus.SetWordWrap(TRUE); m_UserStatus.SetText(L"Status"); m_UserProto.SetAlignment(DT_RIGHT); m_UserProto.SetWordWrap(TRUE); m_UserProto.SetText(L"User"); m_Input.Show(0); m_TextLog.Show(1); m_TextLog.SetScrollbar(&m_Scrollbar); AddObject(&m_Scrollbar); AddObject(&m_TextLog); AddObject(&m_Input); AddObject(&m_InfoText); AddObject(&m_UserName); AddObject(&m_UserStatus); AddObject(&m_UserProto); SetButtonBitmap(0, IDB_UP); SetButtonBitmap(1, IDB_DOWN); SetButtonBitmap(2, IDB_HISTORY); SetButtonBitmap(3, IDB_REPLY); return true; } //************************************************************************ // Shutdown the screen //************************************************************************ bool CChatScreen::Shutdown() { if (!CScreen::Shutdown()) return false; return true; } //************************************************************************ // update's the screens objects ( sizes, fonts etc) //************************************************************************ void CChatScreen::UpdateObjects() { m_bHideTitle = false; m_bHideLabels = !CConfig::GetBoolSetting(SHOW_LABELS); if (IsMaximized()) { if (!m_bHideTitle && !CConfig::GetBoolSetting(MAXIMIZED_TITLE)) m_bHideTitle = true; if (!m_bHideLabels && !CConfig::GetBoolSetting(MAXIMIZED_LABELS)) m_bHideLabels = true; } // Fonts m_TextLog.SetFont(CConfig::GetFont(FONT_SESSION)); m_Input.SetFont(CConfig::GetFont(FONT_SESSION)); m_InfoText.SetFont(CConfig::GetFont(FONT_SESSION)); m_UserName.SetFont(CConfig::GetFont(FONT_TITLE)); m_UserStatus.SetFont(CConfig::GetFont(FONT_TITLE)); m_UserProto.SetFont(CConfig::GetFont(FONT_TITLE)); int w = GetWidth() - 8; // Sizes m_UserName.SetSize(w*0.4, CConfig::GetFontHeight(FONT_TITLE)); m_UserStatus.SetSize(w*0.25, CConfig::GetFontHeight(FONT_TITLE)); m_UserProto.SetSize(w*0.3, CConfig::GetFontHeight(FONT_TITLE)); int iHeight = GetHeight(); iHeight -= m_bHideTitle ? 0 : CConfig::GetFontHeight(FONT_TITLE) + 2; iHeight -= m_bHideLabels ? 0 : 5; m_Input.SetSize(GetWidth() - 5, iHeight); m_TextLog.SetSize(GetWidth() - 5, iHeight); m_InfoText.SetSize(160, 28); m_InfoText.SetOrigin(0, (iHeight - CConfig::GetFontHeight(FONT_SESSION)) / 2); // Origins m_UserName.SetOrigin(8 + w * 0.25, 0); m_UserStatus.SetOrigin(8, 0); m_UserProto.SetOrigin(GetWidth() - w * 0.3, 0); m_TextLog.SetOrigin(0, m_bHideTitle ? 0 : CConfig::GetFontHeight(FONT_TITLE) + 2); m_Input.SetOrigin(0, m_bHideTitle ? 0 : CConfig::GetFontHeight(FONT_TITLE) + 2); m_InfoText.SetOrigin(0, 10); m_UserName.Show(!m_bHideTitle); m_UserStatus.Show(!m_bHideTitle); m_UserProto.Show(!m_bHideTitle); m_Scrollbar.SetOrigin(GetWidth() - 4, (m_bHideTitle ? 0 : CConfig::GetFontHeight(FONT_TITLE) + 2)); m_Scrollbar.SetSize(4, iHeight); // other options m_TextLog.SetLogSize(CConfig::GetIntSetting(SESSION_LOGSIZE)); m_Input.SetBreakKeys(CConfig::GetBoolSetting(SESSION_SENDRETURN) ? KEYS_RETURN : KEYS_CTRL_RETURN); m_Input.ShowSymbols(CConfig::GetBoolSetting(SESSION_SYMBOLS)); ShowButtons(!m_bHideLabels); } //************************************************************************ // update's the screens title labels //************************************************************************ void CChatScreen::UpdateLabels() { tstring strNickname = CAppletManager::GetContactDisplayname(m_hContact); char *szProto = Proto_GetBaseAccountName(m_hContact); m_iStatus = ID_STATUS_OFFLINE; tstring strProto = L""; tstring strStatus = L""; if (szProto != nullptr) { strProto = L"(" + toTstring(szProto) + L")"; m_iStatus = db_get_w(m_hContact, szProto, "Status", ID_STATUS_OFFLINE); } wchar_t *szStatus = Clist_GetStatusModeDescription(m_iStatus, 0); if (szStatus != nullptr) strStatus = toTstring(szStatus); m_UserName.SetText(strNickname.c_str()); m_UserStatus.SetText(strStatus.c_str()); if (m_bContactTyping && CConfig::GetBoolSetting(SESSION_SHOWTYPING)) m_UserProto.SetText(CAppletManager::TranslateString(L"typing..")); else m_UserProto.SetText(strProto.c_str()); } // returns wether the input mode is active bool CChatScreen::IsInputActive() { if (m_eReplyState != REPLY_STATE_NONE) return true; else return false; } //************************************************************************ // returns the chat contact //************************************************************************ MCONTACT CChatScreen::GetContact() { return m_hContact; } //************************************************************************ // sets the screen's chat contact //************************************************************************ bool CChatScreen::SetContact(MCONTACT hContact) { if (hContact == NULL) { m_hContact = NULL; return true; } // Check if the contact is valid char *szProto = Proto_GetBaseAccountName(hContact); m_strProto = toTstring(szProto); CIRCConnection *pIRCCon = CAppletManager::GetInstance()->GetIRCConnection(m_strProto); if (pIRCCon) m_bIRCProtocol = true; else m_bIRCProtocol = false; if (!szProto) return false; if (m_eReplyState != REPLY_STATE_NONE) DeactivateMessageMode(); else if (IsMaximized()) Minimize(); m_bContactTyping = false; m_hContact = hContact; m_TextLog.ClearLog(); UpdateLabels(); LoadHistory(); return true; } //************************************************************************ // loads the contacts history //************************************************************************ void CChatScreen::LoadHistory() { if (!m_hContact) return; char *szProto = Proto_GetBaseAccountName(m_hContact); if (m_bIRCProtocol && Contact::IsGroupChat(m_hContact, szProto)) { if (!CAppletManager::GetInstance()->IsIRCHookEnabled()) { time_t now; tm tm_now; time(&now); localtime_s(&tm_now, &now); AddIncomingMessage(CAppletManager::TranslateString(L"IRC-Chatroom support is disabled!\nYou need to install the patched IRC.dll (see the readme) to use IRC-Chatrooms on the LCD"), &tm_now, true); } else { CIRCHistory *pHistory = CAppletManager::GetInstance()->GetIRCHistory(m_hContact); if (pHistory) { list::iterator iter = pHistory->LMessages.begin(); while (iter != pHistory->LMessages.end()) { if ((*iter).bIsMe) AddOutgoingMessage((*iter).strMessage, &((*iter).Time), true); else AddIncomingMessage((*iter).strMessage, &((*iter).Time), true); iter++; } } } } else { // Get last events from database CEvent Event; list LHandles; MEVENT hEvent = db_event_last(m_hContact); MEVENT hUnread = db_event_firstUnread(m_hContact); if (CConfig::GetBoolSetting(SESSION_LOADDB)) { while (hEvent != NULL && hUnread != NULL) { LHandles.push_front(hEvent); if (CConfig::GetBoolSetting(SESSION_LOADDB) && *(LHandles.begin()) == hUnread) break; hEvent = db_event_prev(m_hContact, hEvent); } } else { for (int i = CConfig::GetIntSetting(SESSION_LOGSIZE); i > 0 && hEvent != NULL; i--) { LHandles.push_front(hEvent); hEvent = db_event_prev(m_hContact, hEvent); } } bool bRead = true; while (!(LHandles.empty())) { if (CAppletManager::TranslateDBEvent(&Event, (LPARAM)m_hContact, (WPARAM)*(LHandles.begin()))) { if (Event.hValue == hUnread) bRead = false; if (Event.eType == EVENT_MSG_RECEIVED) { AddIncomingMessage(Event.strValue, &Event.Time); if (!bRead && CConfig::GetBoolSetting(SESSION_MARKREAD) && !CAppletManager::IsMessageWindowOpen(m_hContact)) CAppletManager::MarkMessageAsRead(m_hContact, Event.hValue); } else AddOutgoingMessage(Event.strValue, &Event.Time); } LHandles.pop_front(); } } } //************************************************************************ // Updates the screen //************************************************************************ bool CChatScreen::Update() { if (!CScreen::Update()) return false; if (CConfig::GetBoolSetting(SESSION_CLOSE)) { if (!CAppletManager::GetInstance()->GetLCDConnection()->IsForeground()) { if (!m_bCloseTimer && CConfig::GetIntSetting(SESSION_CLOSETIMER) != 0) { m_bCloseTimer = true; m_dwCloseTimer = GetTickCount(); } else if (CConfig::GetIntSetting(SESSION_CLOSETIMER) == 0 || GetTickCount() - m_dwCloseTimer >= CConfig::GetIntSetting(SESSION_CLOSETIMER)) { m_bCloseTimer = false; CAppletManager::GetInstance()->ActivateEventScreen(); return true; } } } if (m_bMaximizedTimer && m_dwMaximizedDuration != INFINITE) { if (m_dwMaximizedTimer + m_dwMaximizedDuration <= GetTickCount()) Minimize(); } if (m_eReplyState == REPLY_STATE_INPUT && !m_Input.IsInputActive()) SendCurrentMessage(); // Handle Typing notifications if (IsInputActive()) { if (m_Input.GetLastInputTime() + 10000 <= GetTickCount()) { if (m_bTyping) { m_bTyping = false; CAppletManager::GetInstance()->SendTypingNotification(m_hContact, 0); } } else if (CConfig::GetBoolSetting(SESSION_SENDTYPING) && !m_bTyping) { m_bTyping = true; CAppletManager::GetInstance()->SendTypingNotification(m_hContact, 1); } } else if (m_bTyping) { m_bTyping = false; CAppletManager::GetInstance()->SendTypingNotification(m_hContact, 0); } return true; } //************************************************************************ // Draws the screen //************************************************************************ bool CChatScreen::Draw(CLCDGfx *pGfx) { if (!CScreen::Draw(pGfx)) return false; if (!m_bHideTitle) { int iTitleHeight = CConfig::GetFontHeight(FONT_TITLE) + 1; pGfx->DrawLine(0, iTitleHeight < 6 ? 6 : iTitleHeight, GetWidth(), iTitleHeight < 6 ? 6 : iTitleHeight); int iOffset = (iTitleHeight - 5) / 2; pGfx->DrawBitmap(1, iOffset, 5, 5, CAppletManager::GetInstance()->GetStatusBitmap(m_iStatus)); } return true; } //************************************************************************ // Adds an outgoing message to the log //************************************************************************ void CChatScreen::AddOutgoingMessage(tstring strMessage, tm *time, bool bIRC) { tstring strPrefix = bIRC ? L"" : L">> "; if (CConfig::GetBoolSetting(SESSION_TIMESTAMPS)) strPrefix += CAppletManager::GetFormattedTimestamp(time) + L" "; // adjust the scroll mode m_TextLog.SetAutoscrollMode(SCROLL_LINE); // add the message m_TextLog.AddText(strPrefix + strMessage, true); } //************************************************************************ // Adds an incoming message to the log //************************************************************************ void CChatScreen::AddIncomingMessage(tstring strMessage, tm *time, bool bIRC) { tstring strPrefix = bIRC ? L"" : L"<< "; if (CConfig::GetBoolSetting(SESSION_TIMESTAMPS)) strPrefix += CAppletManager::GetFormattedTimestamp(time) + L" "; // adjust the scroll mode EScrollMode eMode; switch (CConfig::GetIntSetting(SESSION_AUTOSCROLL)) { case SESSION_AUTOSCROLL_FIRST: eMode = SCROLL_MESSAGE; break; case SESSION_AUTOSCROLL_LAST: eMode = SCROLL_LINE; break; default: eMode = SCROLL_NONE; } m_TextLog.SetAutoscrollMode(eMode); // add the message m_TextLog.AddText(strPrefix + strMessage); } //************************************************************************ // activates the input mode //************************************************************************ void CChatScreen::ActivateMessageMode() { m_InfoText.Show(0); m_TextLog.Show(0); m_TextLog.SetScrollbar(nullptr); m_Input.SetScrollbar(&m_Scrollbar); if (m_eReplyState != REPLY_STATE_FAILED) m_Input.Reset(); m_Input.Show(1); m_Input.ActivateInput(); m_eReplyState = REPLY_STATE_INPUT; SetButtonBitmap(2, IDB_BACK); SetButtonBitmap(3, IDB_SEND); if (CConfig::GetBoolSetting(SESSION_REPLY_MAXIMIZED)) Maximize(); else Minimize(); } //************************************************************************ // sends the message //************************************************************************ void CChatScreen::SendCurrentMessage() { if (m_Input.GetText().empty()) { DeactivateMessageMode(); return; } ASSERT(m_eReplyState == REPLY_STATE_INPUT); m_eReplyState = REPLY_STATE_SENDING; m_Input.DeactivateInput(); m_InfoText.SetText(CAppletManager::TranslateString(L"Sending message...")); m_InfoText.Show(1); m_Input.Show(0); m_hMessage = CAppletManager::SendMessageToContact(m_hContact, m_Input.GetText()); if (m_hMessage == NULL) { DeactivateMessageMode(); return; } SetButtonBitmap(2, NULL); SetButtonBitmap(3, NULL); } //************************************************************************ // invalidates the message mode //************************************************************************ void CChatScreen::InvalidateMessageMode(tstring strError) { m_eReplyState = REPLY_STATE_FAILED; m_InfoText.SetText(strError); SetButtonBitmap(2, IDB_BACK); SetButtonBitmap(3, IDB_SEND); if (IsMaximized()) Minimize(); } //************************************************************************ // deactivates the input mode //************************************************************************ void CChatScreen::DeactivateMessageMode() { m_Input.Reset(); m_Input.SetScrollbar(nullptr); m_TextLog.SetScrollbar(&m_Scrollbar); m_TextLog.Show(1); m_InfoText.Show(0); m_Input.Show(0); m_Input.DeactivateInput(); m_eReplyState = REPLY_STATE_NONE; SetButtonBitmap(2, IDB_HISTORY); SetButtonBitmap(3, IDB_REPLY); if (IsMaximized()) Minimize(); } //************************************************************************ // maximizes the content object //************************************************************************ void CChatScreen::Maximize(uint32_t dwTimer) { m_bMaximizedTimer = true; m_dwMaximizedTimer = GetTickCount(); m_dwMaximizedDuration = dwTimer; UpdateObjects(); } //************************************************************************ // minimizes the content object //************************************************************************ void CChatScreen::Minimize() { m_bMaximizedTimer = false; m_dwMaximizedTimer = 0; UpdateObjects(); } //************************************************************************ // returns wether the content is maximized //************************************************************************ bool CChatScreen::IsMaximized() { return m_bMaximizedTimer; } //************************************************************************ // Called when the screen size has changed //************************************************************************ void CChatScreen::OnSizeChanged() { CScreen::OnSizeChanged(); UpdateObjects(); } //************************************************************************ // Called when the applet's configuration has changed //************************************************************************ void CChatScreen::OnConfigChanged() { CScreen::OnConfigChanged(); UpdateObjects(); m_TextLog.ClearLog(); LoadHistory(); } //************************************************************************ // Called when an event is received //************************************************************************ void CChatScreen::OnEventReceived(CEvent *pEvent) { // only let events for this contact pass if (pEvent->hContact != m_hContact && // expect for IRC events without a contact -> global notifications !((pEvent->eType == EVENT_IRC_SENT || pEvent->eType == EVENT_IRC_RECEIVED) && pEvent->hContact == NULL)) return; switch (pEvent->eType) { case EVENT_MESSAGE_ACK: if (pEvent->hValue != m_hMessage) return; if (pEvent->iValue == ACKRESULT_SUCCESS) DeactivateMessageMode(); else InvalidateMessageMode(pEvent->strValue.empty() ? CAppletManager::TranslateString(L"Could not send the message!") : pEvent->strValue); break; case EVENT_IRC_SENT: // Add the message to the log AddOutgoingMessage(pEvent->strValue, &pEvent->Time, true); break; case EVENT_IRC_RECEIVED: // Add the message to the log AddIncomingMessage(pEvent->strValue, &pEvent->Time, true); break; case EVENT_MSG_RECEIVED: // mark it as read if required if (CConfig::GetBoolSetting(SESSION_MARKREAD) && !CAppletManager::IsMessageWindowOpen(m_hContact)) CAppletManager::MarkMessageAsRead(m_hContact, pEvent->hValue); // Add the message to the log AddIncomingMessage(pEvent->strValue, &pEvent->Time); break; case EVENT_MSG_SENT: // Add the message to the log AddOutgoingMessage(pEvent->strValue, &pEvent->Time); break; case EVENT_CONTACT_HIDDEN: // contact is set to hidden if (pEvent->iValue == 1) { // Close the chat screen if the contact is an irc chatroom if (!(m_bIRCProtocol && Contact::IsGroupChat(pEvent->hContact, toNarrowString(m_strProto).c_str()))) break; } else break; case EVENT_CONTACT_DELETED: CAppletManager::GetInstance()->ActivateEventScreen(); break; case EVENT_TYPING_NOTIFICATION: m_bContactTyping = pEvent->iValue != 0; UpdateLabels(); break; case EVENT_STATUS: case EVENT_CONTACT_NICK: case EVENT_SIGNED_OFF: case EVENT_SIGNED_ON: UpdateLabels(); break; } } //************************************************************************ // Called when an LCD-button is pressed //************************************************************************ void CChatScreen::OnLCDButtonDown(int iButton) { switch (m_eReplyState) { case REPLY_STATE_NONE: if (iButton == LGLCDBUTTON_CANCEL) { CAppletManager::GetInstance()->ActivatePreviousScreen(); } else if (iButton == LGLCDBUTTON_BUTTON2 || iButton == LGLCDBUTTON_MENU) CAppletManager::GetInstance()->ActivateEventScreen(); // enter reply mode else if (iButton == LGLCDBUTTON_BUTTON3 || iButton == LGLCDBUTTON_OK) ActivateMessageMode(); else { bool bRes = false; if (iButton == LGLCDBUTTON_BUTTON0 || iButton == LGLCDBUTTON_UP) { bRes = m_TextLog.ScrollUp(); } else if (iButton == LGLCDBUTTON_BUTTON1 || iButton == LGLCDBUTTON_DOWN) { bRes = m_TextLog.ScrollDown(); } if (bRes && CConfig::GetBoolSetting(SESSION_SCROLL_MAXIMIZED)) { Maximize(5000); } } break; case REPLY_STATE_FAILED: if (iButton == LGLCDBUTTON_BUTTON2 || iButton == LGLCDBUTTON_CANCEL) { DeactivateMessageMode(); } else if (iButton == LGLCDBUTTON_BUTTON3 || iButton == LGLCDBUTTON_OK) { ActivateMessageMode(); } else if (iButton == LGLCDBUTTON_MENU) { DeactivateMessageMode(); CAppletManager::GetInstance()->ActivateEventScreen(); } break; case REPLY_STATE_SENDING: break; case REPLY_STATE_INPUT: if (iButton == LGLCDBUTTON_BUTTON0 || iButton == LGLCDBUTTON_UP) { m_Input.ScrollLine(0); } else if (iButton == LGLCDBUTTON_BUTTON1 || iButton == LGLCDBUTTON_DOWN) { m_Input.ScrollLine(1); // send the message } else if (iButton == LGLCDBUTTON_BUTTON3 || iButton == LGLCDBUTTON_OK) { SendCurrentMessage(); // cancel message mode } else if (iButton == LGLCDBUTTON_BUTTON2 || iButton == LGLCDBUTTON_CANCEL) { DeactivateMessageMode(); } break; } } //************************************************************************ // Called when an LCD-button event is repeated //************************************************************************ void CChatScreen::OnLCDButtonRepeated(int iButton) { switch (m_eReplyState) { case REPLY_STATE_NONE: if (iButton < 2) { bool bRes = false; if (iButton == LGLCDBUTTON_BUTTON0) { bRes = m_TextLog.ScrollUp(); } if (bRes && CConfig::GetBoolSetting(SESSION_SCROLL_MAXIMIZED)) Maximize(5000); } break; case REPLY_STATE_INPUT: if (iButton == LGLCDBUTTON_BUTTON0 || iButton == LGLCDBUTTON_UP) { m_Input.ScrollLine(0); } else if (iButton == LGLCDBUTTON_BUTTON1 || iButton == LGLCDBUTTON_DOWN) { m_Input.ScrollLine(1); } } } //************************************************************************ // Called when an LCD-button is released //************************************************************************ void CChatScreen::OnLCDButtonUp(int) { } //************************************************************************ // Called when the screen is activated //************************************************************************ void CChatScreen::OnActivation() { m_bCloseTimer = false; } //************************************************************************ // Called when the screen is deactivated //************************************************************************ void CChatScreen::OnDeactivation() { } //************************************************************************ // Called when the screen has expired //************************************************************************ void CChatScreen::OnExpiration() { }