You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1693 lines
42 KiB
Plaintext
1693 lines
42 KiB
Plaintext
{
|
|
This file is part of R&Q.
|
|
Under same license
|
|
}
|
|
unit chatDlg;
|
|
{$I RnQConfig.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, System.DateUtils, System.Threading, System.Win.TaskbarCore,
|
|
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.ExtCtrls, Vcl.Taskbar, Vcl.Imaging.PNGImage, Generics.Collections,
|
|
RDGlobal, RnQGraphics32, RnQNet, ICQCommon, ICQContacts, ChatBox, events, pluginLib, Murmur2, SpellCheck, Sciter, SciterAPI;
|
|
|
|
{$I NoRTTI.inc}
|
|
|
|
const
|
|
ClrHistBG = 'history.bg';
|
|
|
|
type
|
|
TPanelEx = class(TPanel)
|
|
private
|
|
procedure WMEraseBkgnd(var msg: TWMEraseBkgnd); message WM_ERASEBKGND;
|
|
end;
|
|
|
|
TChatType = (CT_IM, CT_PLUGING);
|
|
|
|
PChatInfo = ^TchatInfo;
|
|
|
|
TchatInfo = class
|
|
public
|
|
ID: IntPtr;
|
|
chatType: TChatType;
|
|
who: TICQContact;
|
|
single: Boolean; // single-message
|
|
lastInputText: string; // last input.text before quoting sequence
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure CheckTypingTime;
|
|
end; // TchatInfo
|
|
|
|
Tchats = class(Tlist)
|
|
function validIdx(i: Integer): boolean;
|
|
function idxOf(c: TICQContact): Integer;
|
|
function idxOfUIN(const uin: TUID): Integer;
|
|
function idxOfID(ID: Integer): Integer;
|
|
function byIdx(i: Integer): TchatInfo;
|
|
function byContact(c: TICQContact): TchatInfo;
|
|
function byUIN(const uid: TUID): TchatInfo;
|
|
function byID(id: Integer): TchatInfo;
|
|
procedure CheckTypingTimeAll;
|
|
end; // Tchats
|
|
|
|
TchatFrm = class(TForm)
|
|
TaskBar: TTaskbar;
|
|
procedure closemenuPopup(Sender: TObject);
|
|
procedure FormResize(Sender: TObject);
|
|
procedure AvtsplitterMoving(Sender: TObject; var NewSize: Integer; var Accept: boolean);
|
|
procedure Close1Click(Sender: TObject);
|
|
procedure Viewinfo1Click(Sender: TObject);
|
|
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure FormClose(Sender: TObject; var Action: TCloseAction);
|
|
procedure FormShow(Sender: TObject);
|
|
procedure chatDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: boolean);
|
|
procedure chatDragDrop(Sender, Source: TObject; X, Y: Integer);
|
|
procedure FormDestroy(Sender: TObject);
|
|
procedure DragDropFiles(var Message: TWMDropFiles); message WM_DROPFILES;
|
|
procedure OnBeforeHeaderSend(Sender: TObject; const Method : String; Headers: TStrings);
|
|
procedure OnSendData(Sender: TObject; Buffer: Pointer; Len: Integer);
|
|
procedure TaskBarThumbButtonClick(Sender: TObject; AButtonID: Integer);
|
|
procedure FormCreate(Sender: TObject);
|
|
protected
|
|
procedure WndProc(var Message: TMessage); override;
|
|
procedure CreateParams(var Params: TCreateParams); override;
|
|
procedure WMEXITSIZEMOVE(var Message: TMessage); message WM_EXITSIZEMOVE;
|
|
procedure WMWINDOWPOSCHANGING(Var msg: TWMWINDOWPOSCHANGING); message WM_WINDOWPOSCHANGING;
|
|
procedure WMAppCommand(var msg: TMessage); message WM_APPCOMMAND;
|
|
procedure WMNCActivate(var msg: TWMNCActivate); message WM_NCACTIVATE;
|
|
private
|
|
FMouseInControl: Boolean;
|
|
procedure CMMouseEnter(var Msg: TMessage); message CM_MOUSEENTER;
|
|
procedure CMMouseLeave(var Msg: TMessage); message CM_MOUSELEAVE;
|
|
public
|
|
chats: Tchats;
|
|
ChatBox: TChatBox;
|
|
selectedUIN: TUID;
|
|
plugBtns: TPlugButtons;
|
|
MainFormWidth: Integer;
|
|
menuWasCancelled: boolean;
|
|
PagesEnumStr: RawByteString;
|
|
DraggingTab: Boolean;
|
|
Initialized: Boolean;
|
|
procedure UpdateChatSettings;
|
|
procedure UpdateChatSmiles;
|
|
procedure LoadChatStickers;
|
|
procedure LoadSearchResults;
|
|
function IsChatOpen(otherHand: TICQContact): boolean;
|
|
function OpenChat(otherHand: TICQContact; ForceActive: Boolean = False; isAuto: Boolean = False): Boolean;
|
|
function AddEvent_OpenChat(otherHand: TICQContact; ev: Thevent): Boolean;
|
|
function AddEvent(c: TICQContact; ev: Thevent): Boolean; overload;
|
|
function OpenOn(c: TICQContact; focus: Boolean = True; pShow: Boolean = True): Boolean;
|
|
procedure Open(focus: Boolean = True);
|
|
function NewIMChannel(c: TICQContact): Integer;
|
|
procedure UpdateAvatar(c: TICQContact);
|
|
function thisChat: TchatInfo;
|
|
function thisChatUID: TUID;
|
|
procedure SetCurrent(idx: Integer);
|
|
procedure UserChanged(c: TICQContact);
|
|
procedure RedrawTabs;
|
|
procedure RedrawTab(c: TICQContact);
|
|
procedure RedrawPluginTab(ci: TchatInfo);
|
|
procedure CloseThisPage;
|
|
procedure CloseAllPages(isAuto: boolean = false);
|
|
procedure ClosePageAt(idx: Integer);
|
|
procedure CloseChat(ci: TchatInfo);
|
|
procedure CloseChatWith(c: TICQContact);
|
|
procedure CloseChatUID(const uid: TUID);
|
|
procedure CloseChatID(ID: Integer);
|
|
function SawAllHere: boolean;
|
|
function isVisible: boolean;
|
|
procedure ApplyFormXY;
|
|
procedure UpdateContactStatus(cnt: TICQContact = nil);
|
|
function pageIdxAt(X, Y: Integer): Integer;
|
|
procedure UpdateChatfrmXY;
|
|
procedure UpdateChatfrmPreview;
|
|
procedure UpdateStatusBar;
|
|
procedure UpdateRelTimes;
|
|
procedure SetStatusbar(const s: String);
|
|
function HasEvent(c: TICQContact; ev: Thevent): Boolean;
|
|
procedure MoveToEvent(c: TICQContact; ev: Thevent);
|
|
procedure SetUnreadEvent(c: TICQContact; ev: Thevent);
|
|
function thisContact: TICQContact;
|
|
procedure flash;
|
|
procedure shake;
|
|
function Pages2String: RawByteString;
|
|
procedure loadPages(const s: RawByteString); overload;
|
|
procedure loadPages(const cl: TRnQCList); overload;
|
|
procedure UpdateGraphics(c: TICQContact = nil);
|
|
procedure ApplyTheme;
|
|
procedure ResetHistory;
|
|
|
|
procedure InitDocument;
|
|
procedure RefreshTaskbarButtons;
|
|
procedure InitSpellCheck;
|
|
procedure SpellCheck;
|
|
procedure SetupChatButtons;
|
|
procedure SetupStickersButton;
|
|
|
|
procedure ApplyTitleColors(active: Boolean);
|
|
end; // TchatFrm
|
|
|
|
function CHAT_TAB_ADD(Control: Integer; iIcon: HIcon; const TabCaption: String): Integer;
|
|
procedure CHAT_TAB_MODIFY(Control: Integer; iIcon: HIcon; const TabCaption: String);
|
|
procedure CHAT_TAB_DELETE(Control: Integer);
|
|
|
|
var
|
|
chatFrm: TchatFrm;
|
|
UploadCallbacks: TCallbacks;
|
|
TabsIconCache: TDictionary |
|
EmbeddedImgs: TDictionary |
|
MouseHook: Cardinal;
|
|
|
|
implementation
|
|
|
|
{$R *.DFM}
|
|
|
|
uses
|
|
Clipbrd, ShellAPI, Themes, Math, Types,
|
|
RQUtil, RDUtils, RnQSysUtils, RnQTips, RnQPics, RnQLangs, RnQGlobal,
|
|
globalLib, outboxlib, utilLib, mainDlg, roasterLib, Protocols_All,
|
|
Protocol_ICQ, ICQConsts,
|
|
RQThemes, themesLib,
|
|
{$IFDEF UNICODE}
|
|
AnsiStrings,
|
|
Character
|
|
{$ENDIF UNICODE};
|
|
|
|
procedure TPanelEx.WMEraseBkgnd(var msg: TWMEraseBkgnd);
|
|
begin
|
|
msg.Result := 1;
|
|
msg.msg := 0;
|
|
end;
|
|
|
|
constructor TchatInfo.Create;
|
|
begin
|
|
inherited;
|
|
end;
|
|
|
|
destructor TchatInfo.Destroy;
|
|
begin
|
|
who := nil;
|
|
inherited;
|
|
end;
|
|
|
|
{ Tchats }
|
|
|
|
{$WARN UNSAFE_CAST OFF}
|
|
function Tchats.idxOfUIN(const uin: TUID): Integer;
|
|
begin
|
|
Result := 0;
|
|
while Result < count do
|
|
begin
|
|
if TchatInfo(items[Result]).chatType = CT_IM then
|
|
if TchatInfo(items[Result]).who.equals(uin) then
|
|
Exit;
|
|
Inc(Result);
|
|
end;
|
|
Result := -1;
|
|
end; // idxOfUIN
|
|
|
|
function Tchats.idxOfID(ID: Integer): Integer;
|
|
begin
|
|
Result := 0;
|
|
while Result < count do
|
|
begin
|
|
if TchatInfo(items[Result]).chatType = CT_PLUGING then
|
|
if TchatInfo(items[Result]).ID = ID then
|
|
Exit;
|
|
Inc(Result);
|
|
end;
|
|
Result := -1;
|
|
end; // idxOfID
|
|
|
|
function Tchats.idxOf(c: TICQContact): Integer;
|
|
begin
|
|
Result := 0;
|
|
while Result < count do
|
|
begin
|
|
if Assigned(items[Result]) then
|
|
if TchatInfo(items[Result]).chatType = CT_IM then
|
|
if TchatInfo(items[Result]).who.equals(c) then
|
|
Exit;
|
|
Inc(Result);
|
|
end;
|
|
Result := -1;
|
|
end; // idxOf
|
|
|
|
function Tchats.byIdx(i: Integer): TchatInfo;
|
|
begin
|
|
Result := nil;
|
|
if validIdx(i) then
|
|
Result := TchatInfo(items[i])
|
|
end; // byIdx
|
|
{$WARN UNSAFE_CAST ON}
|
|
|
|
function Tchats.byContact(c: TICQContact): TchatInfo;
|
|
begin
|
|
Result := byIdx(idxOf(c))
|
|
end;
|
|
|
|
function Tchats.byUIN(const uid: TUID): TchatInfo;
|
|
begin
|
|
Result := byIdx(idxOfUIN(uid))
|
|
end;
|
|
|
|
function Tchats.byID(id: Integer): TchatInfo;
|
|
begin
|
|
Result := byIdx(idxOfID(id))
|
|
end;
|
|
|
|
function Tchats.validIdx(i: Integer): boolean;
|
|
begin
|
|
Result := (i >= 0) and (i < count)
|
|
end;
|
|
|
|
procedure Tchats.CheckTypingTimeAll;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if Assigned(Account.AccProto) then
|
|
if (Account.AccProto.SupportTypingNotif) and (Account.AccProto.IsSendTypingNotif) then
|
|
if count > 0 then
|
|
for i := count - 1 downto 0 do
|
|
if TchatInfo(items[i]).chatType = CT_IM then
|
|
if Assigned(TchatInfo(items[i]).who) then
|
|
TchatInfo(items[i]).CheckTypingTime;
|
|
end;
|
|
|
|
{ TchatFrm }
|
|
|
|
procedure TchatFrm.FormResize(Sender: TObject);
|
|
var
|
|
ch: TchatInfo;
|
|
begin
|
|
UpdateChatfrmXY;
|
|
UpdateChatfrmPreview;
|
|
ch := thisChat;
|
|
if ch = nil then
|
|
Exit;
|
|
if ch.chatType = CT_PLUGING then
|
|
plugins.castEv(PE_SELECTTAB, ch.ID)
|
|
end; // formResize
|
|
|
|
function TchatFrm.AddEvent_OpenChat(otherHand: TICQContact; ev: Thevent): Boolean;
|
|
begin
|
|
OpenChat(otherHand);
|
|
Result := AddEvent(otherHand, ev);
|
|
end; // addEvent_openchat
|
|
|
|
function TchatFrm.AddEvent(c: TICQContact; ev: Thevent): Boolean;
|
|
// tells if ev has been inserted in a list, or can be freed
|
|
var
|
|
ch: TchatInfo;
|
|
begin
|
|
Result := False;
|
|
ch := chats.byContact(c);
|
|
if Assigned(ch) then
|
|
begin
|
|
Result := True;
|
|
ChatBox.AddEvent(c.UID, ev);
|
|
end;
|
|
FreeAndNil(ev);
|
|
end; // AddEvent
|
|
|
|
function TchatFrm.OpenChat(otherHand: TICQContact; ForceActive: Boolean = False; isAuto: Boolean = False): Boolean;
|
|
const
|
|
MaxNILpages = 101;
|
|
var
|
|
i, k: Integer;
|
|
wasEmpty, alreadyThere: boolean;
|
|
cnt: TICQContact;
|
|
firstNILpage, NILcount: Integer;
|
|
begin
|
|
wasEmpty := chats.Count = 0;
|
|
i := chats.idxOf(otherHand);
|
|
Result := i < 0;
|
|
if Result then
|
|
i := NewIMChannel(otherHand);
|
|
|
|
alreadyThere := otherHand.equals(ChatBox.CurrentContact);
|
|
if wasEmpty then
|
|
begin
|
|
if i >= 0 then
|
|
setCurrent(i);
|
|
// if docking.Docked2chat then
|
|
// applyDocking;
|
|
end
|
|
else
|
|
begin
|
|
if not alreadyThere and ForceActive then
|
|
if i >= 0 then
|
|
setCurrent(i)
|
|
else
|
|
setCurrent(chats.idxOf(otherHand));
|
|
|
|
if isAuto then
|
|
begin // protection against bruteforce
|
|
firstNILpage := -1;
|
|
NILcount := 0;
|
|
for k := 0 to chats.count - 1 do
|
|
begin
|
|
if chats.byIdx(k).chatType = CT_IM then
|
|
begin
|
|
cnt := chats.byIdx(k).who;
|
|
if Assigned(cnt) and notInList.exists(cnt) then
|
|
begin
|
|
Inc(NILcount);
|
|
if firstNILpage < 0 then
|
|
firstNILpage := k;
|
|
end;
|
|
end;
|
|
end;
|
|
if (firstNILpage >= 0) and (NILcount > MaxNILpages) then
|
|
ClosePageAt(firstNILpage);
|
|
end;
|
|
end;
|
|
if ForceActive and not Visible then
|
|
Visible := True;
|
|
end;
|
|
|
|
function TchatFrm.IsChatOpen(otherHand: TICQContact): boolean;
|
|
begin
|
|
Result := chats.idxOf(otherHand) >= 0
|
|
end;
|
|
|
|
procedure TchatFrm.ApplyFormXY;
|
|
begin
|
|
with chatfrmXY do
|
|
if Width > 0 then
|
|
if maximized then
|
|
begin
|
|
SetBounds(Left, Top, Width, Height);
|
|
WindowState := wsMaximized;
|
|
end
|
|
else
|
|
begin
|
|
SetBounds(Left, Top, Width, Height);
|
|
WindowState := wsNormal
|
|
end;
|
|
end; // ApplyFormXY
|
|
|
|
procedure TchatFrm.InitDocument;
|
|
begin
|
|
if Initialized then
|
|
Exit;
|
|
|
|
chats := Tchats.Create;
|
|
plugBtns := TPlugButtons.Create;
|
|
|
|
DraggingTab := False;
|
|
|
|
DragAcceptFiles(self.handle, true);
|
|
ApplyFormXY;
|
|
applyTaskButton(self);
|
|
|
|
TabsIconCache := TDictionary |
|
EmbeddedImgs := TDictionary |
|
|
|
UploadCallbacks := TCallbacks.Create;
|
|
UploadCallbacks.OnBeforeHeaderSend := OnBeforeHeaderSend;
|
|
UploadCallbacks.OnSendData := OnSendData;
|
|
|
|
ChatBox := TChatBox.Create(Self);
|
|
with ChatBox do
|
|
begin
|
|
Enabled := False;
|
|
Align := alClient;
|
|
|
|
OnDragOver := chatDragOver;
|
|
OnDragDrop := chatDragDrop;
|
|
|
|
Load;
|
|
end;
|
|
|
|
theme.smileNotify := ChatBox.ReloadSmiles;
|
|
if EnableStickers then
|
|
begin
|
|
ChatBox.PreloadPickers;
|
|
ChatBox.LoadStickers;
|
|
end;
|
|
CreateThreading;
|
|
|
|
Initialized := True;
|
|
end;
|
|
|
|
procedure TchatFrm.InitSpellCheck;
|
|
begin
|
|
DoInitSpellCheck;
|
|
end;
|
|
|
|
procedure TchatFrm.SpellCheck;
|
|
begin
|
|
DoSpellCheck;
|
|
end;
|
|
|
|
procedure TchatFrm.SetupChatButtons;
|
|
begin
|
|
ChatBox.SetupChatButtons;
|
|
end;
|
|
|
|
procedure TchatFrm.SetupStickersButton;
|
|
begin
|
|
ChatBox.SetupStickersBtn(EnableStickers);
|
|
end;
|
|
|
|
procedure TchatFrm.SetCurrent(idx: Integer);
|
|
var
|
|
ch: TchatInfo;
|
|
begin
|
|
if idx < 0 then
|
|
Exit;
|
|
|
|
ch := chats.byIdx(idx);
|
|
if ch.chatType = CT_PLUGING then
|
|
begin
|
|
//OutputDebugString(PChar('setting tab to plugin ' + IntToStr(ch.ID)));
|
|
ChatBox.SwitchToPage(ch.ID);
|
|
end
|
|
else
|
|
begin
|
|
//OutputDebugString(PChar('setting tab to chat with ' + String(ch.who.UID)));
|
|
ChatBox.SwitchToPage(chats.byIdx(idx).who.UID);
|
|
end;
|
|
end; // SetCurrent
|
|
|
|
procedure TchatFrm.UserChanged(c: TICQContact);
|
|
var
|
|
i: Integer;
|
|
ch: TchatInfo;
|
|
begin
|
|
if c = nil then
|
|
Exit;
|
|
ch := thisChat;
|
|
if ch = nil then
|
|
Exit;
|
|
i := chats.idxOf(c);
|
|
if i < 0 then
|
|
Exit;
|
|
UpdateContactStatus(c);
|
|
RefreshTaskbarButtons;
|
|
end; // UserChanged
|
|
|
|
function TchatFrm.OpenOn(c: TICQContact; focus: Boolean = True; pShow: Boolean = True): Boolean;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := False;
|
|
if c = nil then
|
|
Exit;
|
|
i := chats.idxOf(c);
|
|
if i < 0 then
|
|
begin
|
|
Result := True;
|
|
i := NewIMChannel(c);
|
|
end;
|
|
if i >= 0 then
|
|
SetCurrent(i);
|
|
if pShow then
|
|
Open(focus);
|
|
end; // openOn
|
|
|
|
function TchatFrm.NewIMChannel(c: TICQContact): Integer;
|
|
var
|
|
chat: TchatInfo;
|
|
begin
|
|
chat := TchatInfo.Create;
|
|
chat.who := c;
|
|
chat.chatType := CT_IM;
|
|
chat.single := singleDefault;
|
|
chat.who.typing.bIAmTyping := false;
|
|
chats.Add(chat);
|
|
Result := chats.Count - 1;
|
|
ChatBox.OpenPage(c);
|
|
// ChatBox.CheckServerHistory(c);
|
|
UpdateAvatar(c);
|
|
Resize;
|
|
saveListsDelayed := true;
|
|
RedrawTab(c);
|
|
RefreshTaskbarButtons;
|
|
end; // NewIMChannel
|
|
|
|
procedure TchatFrm.UpdateAvatar(c: TICQContact);
|
|
var
|
|
ci: TchatInfo;
|
|
i: Integer;
|
|
begin
|
|
ci := nil;
|
|
i := chats.idxOf(c);
|
|
if i >= 0 then
|
|
begin
|
|
ci := chats.byIdx(i);
|
|
if Assigned(ci) and Assigned(ci.who) then
|
|
begin
|
|
// if (c.icon.ToShow = IS_NONE) or ((c.icon.ToShow < IS_NONE) and (not Assigned(c.icon.bmp) or (not c.icon.IsBmp and (c.icon_Path = '')))) then
|
|
if c.icon.ToShow = IS_NONE then
|
|
ChatBox.ClearAvatar(ci.who.UID)
|
|
else
|
|
ChatBox.UpdateAvatar(ci.who.UID);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TchatInfo.CheckTypingTime;
|
|
begin
|
|
try
|
|
if (chatType = CT_IM) and Assigned(who) then
|
|
if (who.typing.bIAmTyping) and ((Now - who.typing.TypingTime) * SecsPerDay > TypingInterval) then
|
|
Account.AccProto.InputChangedFor(TICQContact(who), False, True);
|
|
except
|
|
end;
|
|
end;
|
|
|
|
function TchatFrm.thisChat: TchatInfo;
|
|
begin
|
|
if not Assigned(chats) or (chats.count = 0) then
|
|
Result := nil
|
|
else
|
|
Result := chats.byContact(ChatBox.CurrentContact);
|
|
end;
|
|
|
|
function TchatFrm.thisContact: TICQContact;
|
|
var
|
|
ch: TchatInfo;
|
|
begin
|
|
ch := thisChat;
|
|
if ch = nil then
|
|
Result := nil
|
|
else if ch.chatType = CT_IM then
|
|
thisContact := ch.who
|
|
else
|
|
Result := nil;
|
|
end; // thisContact
|
|
|
|
function TchatFrm.thisChatUID: TUID;
|
|
var
|
|
cnt: TICQContact;
|
|
begin
|
|
cnt := thisContact;
|
|
|
|
if Assigned(cnt) then
|
|
Result := cnt.UID2cmp
|
|
else
|
|
Result := '';
|
|
end;
|
|
|
|
function TchatFrm.pageIdxAt(X, Y: Integer): Integer;
|
|
var
|
|
R: TRect;
|
|
begin
|
|
Result := 0;
|
|
while Result < chats.count do
|
|
begin
|
|
// SendMessage(pagectrl.handle, TCM_GETITEMRECT, WPARAM(Result), LPARAM(@R));
|
|
if Types.ptInRect(R, Types.point(X, Y)) then
|
|
exit;
|
|
Inc(Result);
|
|
end;
|
|
Result := -1;
|
|
end; // pageIdxAt
|
|
|
|
procedure TchatFrm.CloseThisPage;
|
|
var
|
|
ch: TchatInfo;
|
|
begin
|
|
if DraggingTab then
|
|
Exit;
|
|
|
|
ch := thisChat;
|
|
|
|
if Assigned(ch) then
|
|
CloseChat(ch);
|
|
end;
|
|
|
|
procedure TchatFrm.UpdateGraphics(c: TICQContact = nil);
|
|
var
|
|
ch: TchatInfo;
|
|
begin
|
|
ch := thisChat;
|
|
if ch = nil then
|
|
Exit;
|
|
if ch.chatType = CT_PLUGING then
|
|
Exit;
|
|
if Assigned(c) and not ch.who.equals(c) then
|
|
Exit;
|
|
ChatBox.SetupSingleBtn(ch.single);
|
|
UpdateContactStatus;
|
|
UpdateStatusBar;
|
|
RefreshTaskbarButtons;
|
|
end; // UpdateGraphics
|
|
|
|
procedure TchatFrm.ApplyTheme;
|
|
begin
|
|
ChatBox.ApplyTheme;
|
|
end;
|
|
|
|
procedure TchatFrm.ResetHistory;
|
|
begin
|
|
ChatBox.ResetHistory;
|
|
end;
|
|
|
|
procedure TchatFrm.Close1Click(Sender: TObject);
|
|
begin
|
|
CloseThisPage
|
|
end;
|
|
|
|
procedure TchatFrm.Viewinfo1Click(Sender: TObject);
|
|
var
|
|
cnt: TICQContact;
|
|
begin
|
|
cnt := thisContact;
|
|
if Assigned(cnt) then
|
|
cnt.ViewInfo;
|
|
end;
|
|
|
|
function TchatFrm.SawAllHere: Boolean;
|
|
const
|
|
ClearEvents = [EK_msg, EK_auth, EK_authDenied, EK_addedYou];
|
|
var
|
|
c: TICQContact;
|
|
ch: TChatInfo;
|
|
k: Integer;
|
|
ev0: Thevent;
|
|
Found: Boolean;
|
|
begin
|
|
Result := False;
|
|
Found := False;
|
|
if eventQ.Count = 0 then
|
|
Exit;
|
|
ch := thisChat;
|
|
if ch = nil then
|
|
Exit;
|
|
if ch.chatType <> CT_IM then
|
|
Exit;
|
|
c := ch.who;
|
|
|
|
k := -1;
|
|
repeat
|
|
k := eventQ.getNextEventFor(c, k);
|
|
if (k >= 0) and (k < eventQ.count) then
|
|
begin
|
|
ev0 := eventQ.items[k];
|
|
if ev0.Kind in ClearEvents then
|
|
begin
|
|
Found := True;
|
|
eventQ.removeAt(k);
|
|
if BE_history in behaviour[ev0.Kind].trig then
|
|
if not chatFrm.HasEvent(c, ev0) then
|
|
chatFrm.AddEvent(c, ev0.clone);
|
|
try
|
|
FreeAndNil(ev0);
|
|
except end;
|
|
end else
|
|
Inc(k);
|
|
end else
|
|
k := -1;
|
|
until (k < 0);
|
|
|
|
if Found then
|
|
begin
|
|
Result := True;
|
|
roasterLib.UpdateInPlace(c);
|
|
SaveInboxDelayed := true;
|
|
end;
|
|
|
|
TipRemove(c);
|
|
end; // SawAllHere
|
|
|
|
procedure TchatFrm.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
var
|
|
ch: TchatInfo;
|
|
begin
|
|
ch := thisChat;
|
|
if ch = nil then
|
|
Exit;
|
|
|
|
if Shift = [] then
|
|
case Key of
|
|
VK_BROWSER_BACK:
|
|
ChatBox.SwitchToPrevPage;
|
|
VK_BROWSER_FORWARD:
|
|
ChatBox.SwitchToNextPage;
|
|
end
|
|
else if (Shift = [ssAlt]) and (ch.chatType = CT_IM) then
|
|
case Key of
|
|
VK_M:
|
|
begin
|
|
useSmiles := not useSmiles;
|
|
UpdateChatSettings;
|
|
UpdateChatSmiles;
|
|
end;
|
|
end
|
|
else if (Shift = [ssCtrl]) or (Shift = [ssCtrl, ssShift]) then
|
|
case Key of
|
|
VK_TAB:
|
|
begin
|
|
Key := 0;
|
|
if ssShift in Shift then
|
|
ChatBox.SwitchToPrevPage
|
|
else
|
|
ChatBox.SwitchToNextPage;
|
|
end;
|
|
end;
|
|
|
|
if (Shift = [ssAlt]) or (Shift = [ssAlt, ssCtrl]) then
|
|
case Key of
|
|
VK_LEFT:
|
|
ChatBox.SwitchToPrevPage;
|
|
VK_RIGHT:
|
|
ChatBox.SwitchToNextPage;
|
|
end
|
|
else if Shift = [ssCtrl] then
|
|
case Key of
|
|
VK_C:
|
|
if ch.chatType = CT_IM then
|
|
ChatBox.copySel2Clpb;
|
|
VK_F5:
|
|
ChatBox.SwitchToPrevPage;
|
|
VK_F6:
|
|
ChatBox.SwitchToNextPage;
|
|
VK_F4, VK_W:
|
|
try
|
|
SawAllHere;
|
|
CloseThisPage;
|
|
Key := 0;
|
|
// Shift := [];
|
|
Exit;
|
|
except end;
|
|
end;
|
|
|
|
if Assigned(ch) and (ch.chatType = CT_PLUGING) then
|
|
SendMessage(ch.ID, WM_KEYDOWN, WPARAM(Key), 0);
|
|
inherited;
|
|
end; // KeyDown
|
|
|
|
procedure TchatFrm.Open(focus: Boolean = True);
|
|
var
|
|
bak: Thandle;
|
|
begin
|
|
if chats.Count = 0 then
|
|
Exit;
|
|
if not Visible then
|
|
bak := GetForegroundWindow
|
|
else
|
|
bak := 0;
|
|
showForm(self);
|
|
if (bak > 0) and not focus then
|
|
ForceForegroundWindow(bak);
|
|
SetWindowPos(handle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE + SWP_NOSIZE); // bring it atop if it is not
|
|
if focus then
|
|
ForceForegroundWindow(handle);
|
|
ChatBox.SetFocus;
|
|
end; // open
|
|
|
|
function TchatFrm.IsVisible: Boolean;
|
|
begin
|
|
Result := Visible and (GetForegroundWindow = Handle);
|
|
end;
|
|
|
|
procedure TchatFrm.FormCreate(Sender: TObject);
|
|
begin
|
|
Initialized := False
|
|
end;
|
|
|
|
procedure TchatFrm.FormClose(Sender: TObject; var Action: TCloseAction);
|
|
begin
|
|
UpdateChatfrmXY;
|
|
TabsIconCache.Clear;
|
|
ChatBox.Enabled := False;
|
|
if chats.Count = 0 then
|
|
EmbeddedImgs.Clear;
|
|
end; // form close
|
|
|
|
procedure TchatFrm.UpdateContactStatus(cnt: TICQContact = nil);
|
|
begin
|
|
if cnt = nil then
|
|
cnt := thisContact;
|
|
with ChatBox do
|
|
begin
|
|
if cnt = nil then
|
|
begin
|
|
SetSendBtnImage(status2imgName(byte(SC_UNK), False));
|
|
Exit;
|
|
end;
|
|
SetSendBtnImage(rosterImgNameFor(cnt));
|
|
|
|
if (thisChat.chatType = CT_IM) and not (thisChat.who = nil) then
|
|
SetupBuzzBtn(thisChat.who.CanBuzz)
|
|
else
|
|
SetupBuzzBtn(False);
|
|
end;
|
|
RedrawTab(cnt);
|
|
end; // UpdateContactStatus
|
|
|
|
procedure TchatFrm.ClosePageAt(idx: Integer);
|
|
var
|
|
ch: TchatInfo;
|
|
cnt: TICQContact;
|
|
id: Integer;
|
|
ltype: TChatType;
|
|
begin
|
|
ch := chats.byIdx(idx);
|
|
if ch = nil then
|
|
Exit;
|
|
|
|
cnt := ch.who;
|
|
id := ch.ID;
|
|
ltype := ch.chatType;
|
|
ChatBox.LastContact := cnt;
|
|
|
|
if ltype = CT_PLUGING then
|
|
plugins.castEv(PE_CLOSETAB, ch.ID)
|
|
else if ltype = CT_IM then
|
|
Account.AccProto.InputChangedFor(TICQContact(ch.who), True);
|
|
|
|
try
|
|
chats.Items[idx] := nil;
|
|
chats.Delete(idx);
|
|
FreeAndNil(ch);
|
|
except end;
|
|
|
|
if ltype = CT_PLUGING then
|
|
ChatBox.ClosePage(id)
|
|
else if ltype = CT_IM then
|
|
ChatBox.ClosePage(cnt.UID);
|
|
|
|
if userTime > 0 then
|
|
saveListsDelayed := true;
|
|
RefreshTaskbarButtons;
|
|
end; // ClosePageAt
|
|
|
|
procedure TchatFrm.CloseChat(ci: TchatInfo);
|
|
begin
|
|
if ci = nil then
|
|
Exit;
|
|
if ci.chatType = CT_IM then
|
|
ClosePageAt(chats.idxOf(ci.who))
|
|
else
|
|
ClosePageAt(chats.idxOfID(ci.ID));
|
|
end;
|
|
|
|
procedure TchatFrm.CloseChatWith(c: TICQContact);
|
|
begin
|
|
ClosePageAt(chats.idxOf(c))
|
|
end;
|
|
|
|
procedure TchatFrm.CloseChatUID(const uid: TUID);
|
|
begin
|
|
ClosePageAt(chats.idxOfUIN(uid))
|
|
end;
|
|
|
|
procedure TchatFrm.CloseChatID(ID: Integer);
|
|
begin
|
|
ClosePageAt(chats.idxOfID(ID));
|
|
end;
|
|
|
|
procedure TchatFrm.FormShow(Sender: TObject);
|
|
begin
|
|
theme.pic2ico(RQteFormIcon, PIC_MSG, icon);
|
|
ApplyFormXY;
|
|
ChatBox.Enabled := True;
|
|
UpdateChatfrmPreview;
|
|
UpdateContactStatus;
|
|
end;
|
|
|
|
procedure TchatFrm.CloseAllPages(isAuto: boolean = false);
|
|
begin
|
|
if isAuto then
|
|
PagesEnumStr := Pages2String
|
|
else
|
|
PagesEnumStr := '';
|
|
|
|
while chats.Count > 0 do
|
|
ClosePageAt(0);
|
|
end; // CloseAllPages
|
|
|
|
procedure TchatFrm.RedrawTabs;
|
|
var
|
|
i: Integer;
|
|
ch: TchatInfo;
|
|
begin
|
|
for i := 0 to chats.Count - 1 do
|
|
begin
|
|
ch := chats.byIdx(i);
|
|
if Assigned(ch) and Assigned(ch.who) then
|
|
RedrawTab(ch.who);
|
|
end;
|
|
end;
|
|
|
|
procedure TchatFrm.RedrawTab(c: TICQContact);
|
|
var
|
|
ci: TchatInfo;
|
|
ev: Thevent;
|
|
tabPic, add: TPicName;
|
|
png, pngadd: TPNGImage;
|
|
hash, hashadd: LongWord;
|
|
mem: TMemoryStream;
|
|
begin
|
|
ci := chats.byContact(c);
|
|
if ci = nil then
|
|
Exit;
|
|
|
|
tabPic := '';
|
|
ev := eventQ.firstEventFor(c);
|
|
if Assigned(ev) and ((blinking or Account.AccProto.GetStatusDisable.blinking) or not blinkWithStatus) then
|
|
begin
|
|
//OutputDebugString(PChar('RedrawTab ' + String(ci.who.UID) + ': ' + booltostr(blinking, true) + ', ' + booltostr(c.fProto.getStatusDisable.blinking, true)));
|
|
if (blinking or Account.AccProto.GetStatusDisable.blinking) then
|
|
tabPic := ev.pic
|
|
else
|
|
tabPic := c.statusImg
|
|
end
|
|
else
|
|
begin
|
|
if c.typing.bIsTyping then
|
|
tabPic := PIC_TYPING
|
|
else if showStatusOnTabs then
|
|
tabPic := c.statusImg
|
|
else
|
|
tabPic := '';
|
|
end;
|
|
|
|
add := '';
|
|
if TICQContact(c).Official then
|
|
add := PIC_OFFICIAL;
|
|
|
|
hash := 0;
|
|
hashadd := 0;
|
|
if not (tabPic = '') then
|
|
begin
|
|
// Main icon
|
|
if theme.Pic2PNG(tabPic, png) then
|
|
if Assigned(png) then
|
|
begin
|
|
mem := TMemoryStream.Create;
|
|
try
|
|
png.SaveToStream(mem);
|
|
hash := CalcMurmur2(mem);
|
|
finally
|
|
FreeAndNil(mem);
|
|
end;
|
|
end;
|
|
|
|
if not (hash = 0) then
|
|
if TabsIconCache.ContainsKey(hash) then
|
|
FreeAndNil(png)
|
|
else if Assigned(png) then
|
|
TabsIconCache.AddOrSetValue(hash, png);
|
|
|
|
// Additional icon in the bottom right corner
|
|
if not (add = '') then
|
|
begin
|
|
if theme.Pic2PNG(add, pngadd) then
|
|
if Assigned(pngadd) then
|
|
begin
|
|
mem := TMemoryStream.Create;
|
|
try
|
|
pngadd.SaveToStream(mem);
|
|
hashadd := CalcMurmur2(mem);
|
|
finally
|
|
FreeAndNil(mem);
|
|
end;
|
|
end;
|
|
|
|
if not (hashadd = 0) then
|
|
if TabsIconCache.ContainsKey(hashadd) then
|
|
FreeAndNil(pngadd)
|
|
else if Assigned(pngadd) then
|
|
TabsIconCache.AddOrSetValue(hashadd, pngadd);
|
|
end;
|
|
end;
|
|
ChatBox.RedrawTab(c, hash, hashadd);
|
|
end;
|
|
|
|
procedure TchatFrm.RedrawPluginTab(ci: TchatInfo);
|
|
var
|
|
tabPic: TPicName;
|
|
png: TPNGImage;
|
|
hash: LongWord;
|
|
mem: TMemoryStream;
|
|
begin
|
|
if ci = nil then
|
|
Exit;
|
|
|
|
hash := 0;
|
|
tabPic := 'plugintab' + IntToStr(ci.ID);
|
|
if theme.Pic2PNG(tabPic, png) then
|
|
if Assigned(png) then
|
|
begin
|
|
mem := TMemoryStream.Create;
|
|
try
|
|
png.SaveToStream(mem);
|
|
hash := CalcMurmur2(mem);
|
|
finally
|
|
FreeAndNil(mem);
|
|
end;
|
|
end;
|
|
|
|
if not (hash = 0) then
|
|
if TabsIconCache.ContainsKey(hash) then
|
|
FreeAndNil(png)
|
|
else if Assigned(png) then
|
|
TabsIconCache.AddOrSetValue(hash, png);
|
|
|
|
ChatBox.RedrawTab(ci.ID, ci.lastInputText, hash);
|
|
end;
|
|
|
|
procedure TchatFrm.WndProc(var Message: TMessage);
|
|
begin
|
|
case Message.Msg of
|
|
WM_SYSCOMMAND:
|
|
UpdateChatfrmXY;
|
|
|
|
WM_MOUSEWHEEL, WM_VSCROLL:
|
|
if (Assigned(chats)) and not (thisChat = nil) and (thisChat.chatType = CT_IM) then
|
|
if Message.WParam shr 31 > 0 then
|
|
ChatBox.ScrollWheel(+1)
|
|
else
|
|
ChatBox.ScrollWheel(-1);
|
|
|
|
WM_KEYDOWN:
|
|
if (thisChat <> nil) and (thisChat.chatType = CT_PLUGING) then
|
|
SendMessage(thisChat.ID, Message.Msg, Message.WParam, Message.LParam);
|
|
|
|
WM_HELP:
|
|
Exit;
|
|
|
|
// WM_MOUSEHOVER:
|
|
// OutputDebugString(PChar('WM_MOUSEHOVER'));
|
|
// WM_MOUSELEAVE:
|
|
// OutputDebugString(PChar('WM_MOUSELEAVE'));
|
|
end;
|
|
inherited;
|
|
end;
|
|
|
|
function stripProtocol(const stringData: String): String;
|
|
begin
|
|
if StartsText('uin:', stringData) then
|
|
Result := copy(stringData, 5, length(stringData))
|
|
else if StartsText('link:', stringData) then
|
|
Result := copy(stringData, 6, length(stringData))
|
|
else if StartsText('mailto:', stringData) then
|
|
Result := copy(stringData, 8, length(stringData))
|
|
else
|
|
Result := stringData;
|
|
end;
|
|
|
|
procedure TchatFrm.chatDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: boolean);
|
|
begin
|
|
// Accept := Source = mainDlg.RnQmain.roster
|
|
end;
|
|
|
|
procedure TchatFrm.chatDragDrop(Sender, Source: TObject; X, Y: Integer);
|
|
var
|
|
cl: TRnQCList;
|
|
begin
|
|
if (clickedContact = nil) or (thisContact = nil) then
|
|
Exit;
|
|
cl := TRnQCList.Create;
|
|
cl.Add(clickedContact);
|
|
OutboxAdd(OE_contacts, thisContact, 0, cl);
|
|
cl.free;
|
|
end;
|
|
|
|
procedure TchatFrm.UpdateChatfrmXY;
|
|
begin
|
|
if not Visible then
|
|
Exit;
|
|
if WindowState <> wsMaximized then
|
|
begin
|
|
chatfrmXY.Top := Top;
|
|
chatfrmXY.Left := Left;
|
|
chatfrmXY.Height := Height;
|
|
chatfrmXY.Width := Width;
|
|
end;
|
|
if WindowState <> wsMinimized then
|
|
chatfrmXY.maximized := WindowState = wsMaximized;
|
|
end; // UpdatechatfrmXY
|
|
|
|
procedure TchatFrm.UpdateChatfrmPreview;
|
|
begin
|
|
TaskBar.PreviewClipRegion.Height := Min(200, ClientHeight);
|
|
TaskBar.PreviewClipRegion.Width := Min(420, ClientWidth);
|
|
TaskBar.ApplyClipAreaChanges;
|
|
end;
|
|
|
|
procedure TchatFrm.UpdateStatusBar;
|
|
begin
|
|
ChatBox.UpdateStatusBar;
|
|
end;
|
|
|
|
procedure TchatFrm.UpdateRelTimes;
|
|
begin
|
|
ChatBox.UpdateRelTimes;
|
|
end;
|
|
|
|
procedure TchatFrm.SetStatusbar(const s: String);
|
|
var
|
|
hint: String;
|
|
begin
|
|
if IsUploading then
|
|
hint := GetTranslation('Uploading file') + ': ' + IntToStr(Trunc(UploadedSize / UploadSize * 100)) + '%'
|
|
else
|
|
hint := s;
|
|
|
|
ChatBox.SetStatusbarHint(hint);
|
|
|
|
if CheckWin32Version(6, 1) then
|
|
with TaskBar do begin
|
|
if (UploadedSize < UploadSize) and IsUploading then
|
|
begin
|
|
ProgressState := TTaskBarProgressState.Normal;
|
|
ProgressValue := Trunc(UploadedSize / UploadSize * 100);
|
|
end
|
|
else
|
|
begin
|
|
ProgressState := TTaskBarProgressState.None;
|
|
ProgressValue := 0;
|
|
end;
|
|
ApplyProgressChanges;
|
|
end;
|
|
end;
|
|
|
|
procedure TchatFrm.MoveToEvent(c: TICQContact; ev: Thevent);
|
|
begin
|
|
ChatBox.MoveToTime(c.UID, ev.when);
|
|
end;
|
|
|
|
function TchatFrm.HasEvent(c: TICQContact; ev: Thevent): Boolean;
|
|
var
|
|
ch: TchatInfo;
|
|
tlast: TDateTime;
|
|
begin
|
|
Result := False;
|
|
ch := chats.byContact(c);
|
|
if not Assigned(ch) then
|
|
Exit;
|
|
|
|
if logpref.writehistory and (BE_save in behaviour[ev.kind].trig) then
|
|
Result := True
|
|
else
|
|
begin
|
|
tlast := ChatBox.GetLastEventTime(c.UID);
|
|
if tlast > 0 then
|
|
Result := CompareDateTime(tlast, ev.when) >= 0;
|
|
end;
|
|
end;
|
|
|
|
procedure TchatFrm.SetUnreadEvent(c: TICQContact; ev: Thevent);
|
|
var
|
|
ch: TchatInfo;
|
|
begin
|
|
ch := chats.byContact(c);
|
|
if not Assigned(ch) then
|
|
Exit;
|
|
|
|
ChatBox.SetFirstUnreadEvent(c.UID, ev.when);
|
|
end;
|
|
|
|
procedure TchatFrm.flash;
|
|
var
|
|
rec: FLASHWINFO;
|
|
begin
|
|
// if doFlashChat then
|
|
begin
|
|
rec.cbSize := sizeOf(rec);
|
|
rec.hwnd := handle;
|
|
rec.dwFlags := FLASHW_CAPTION OR FLASHW_TRAY OR FLASHW_TIMERNOFG;
|
|
rec.dwTimeout := 0;
|
|
rec.uCount := dword(-1);
|
|
flashWindowEx(rec);
|
|
end;
|
|
end; // flash
|
|
|
|
procedure TchatFrm.shake;
|
|
const
|
|
MAXDELTA = 8;
|
|
SHAKETIMES = 150;
|
|
var
|
|
Task: ITask;
|
|
oRect, wRect: TRect;
|
|
wHandle: HWND;
|
|
begin
|
|
wHandle := chatFrm.handle;
|
|
GetWindowRect(wHandle, wRect);
|
|
oRect := wRect;
|
|
Randomize;
|
|
|
|
Task := TTask.Create(procedure()
|
|
var
|
|
cnt: Integer;
|
|
begin
|
|
for cnt := 0 to SHAKETIMES do
|
|
begin
|
|
wRect := oRect;
|
|
Types.OffsetRect(wRect, Round(Random(2 * MAXDELTA) - MAXDELTA), 0);
|
|
MoveWindow(wHandle, wRect.Left, wRect.Top, wRect.Right - wRect.Left, wRect.Bottom - wRect.Top, True);
|
|
Sleep(10);
|
|
end;
|
|
MoveWindow(wHandle, oRect.Left, oRect.Top, oRect.Right - oRect.Left, oRect.Bottom - oRect.Top, True);
|
|
end, TThreadPool.Default);
|
|
Task.Start;
|
|
end;
|
|
|
|
function TchatFrm.Pages2String: RawByteString;
|
|
var
|
|
i: Integer;
|
|
ch: TchatInfo;
|
|
begin
|
|
if (userTime < 0) and (chats.count = 0) then
|
|
Result := PagesEnumStr
|
|
else
|
|
begin
|
|
Result := '';
|
|
for i := 0 to chats.Count - 1 do
|
|
try
|
|
ch := chats.byIdx(i);
|
|
if Assigned(ch) and (ch.chatType = CT_IM) then
|
|
Result := Result + UTF(ch.who.uid) + CRLF;
|
|
except end;
|
|
end;
|
|
end;
|
|
|
|
procedure TchatFrm.loadPages(const s: RawByteString);
|
|
var
|
|
i: Integer;
|
|
chats: TStringList;
|
|
begin
|
|
chats := TStringList.Create;
|
|
chats.Text := s;
|
|
|
|
for i := 0 to chats.Count - 1 do
|
|
openOn(Account.AccProto.GetContact(UnUTF(chats[i])));
|
|
|
|
open(true);
|
|
chats.Free;
|
|
end; // loadPages
|
|
|
|
procedure TchatFrm.loadPages(const cl: TRnQCList);
|
|
var
|
|
cnt: TICQContact;
|
|
begin
|
|
for cnt in cl do
|
|
openOn(cnt);
|
|
open(True);
|
|
end;
|
|
|
|
procedure TchatFrm.AvtsplitterMoving(Sender: TObject; var NewSize: Integer; var Accept: boolean);
|
|
begin
|
|
Accept := NewSize > 0;
|
|
end;
|
|
|
|
procedure TchatFrm.FormDestroy(Sender: TObject);
|
|
begin
|
|
FreeAndNil(plugBtns);
|
|
FreeAndNil(ChatBox);
|
|
FreeAndNil(chats);
|
|
FreeAndNil(TabsIconCache);
|
|
FreeAndNil(EmbeddedImgs);
|
|
FreeAndNil(UploadCallbacks);
|
|
ReleaseThreading;
|
|
end;
|
|
|
|
procedure TchatFrm.UpdateChatSettings;
|
|
begin
|
|
ChatBox.InitSettings;
|
|
end;
|
|
|
|
procedure TchatFrm.UpdateChatSmiles;
|
|
begin
|
|
ChatBox.UpdateSmiles;
|
|
end;
|
|
|
|
procedure TchatFrm.LoadChatStickers;
|
|
begin
|
|
ChatBox.LoadStickers;
|
|
end;
|
|
|
|
procedure TchatFrm.LoadSearchResults;
|
|
begin
|
|
ChatBox.LoadSearchResults;
|
|
end;
|
|
|
|
// ----------------------------------------------------------------------------------------------------------------------
|
|
|
|
function CHAT_TAB_ADD(Control: Integer; iIcon: HIcon; const TabCaption: string): Integer;
|
|
var
|
|
chat: TchatInfo;
|
|
i: Integer;
|
|
begin
|
|
i := chatFrm.chats.idxOfID(Control);
|
|
if chatFrm.chats.validIdx(i) then
|
|
begin
|
|
chatFrm.setCurrent(i);
|
|
chatFrm.Resize;
|
|
Result := -1;
|
|
Exit;
|
|
end;
|
|
|
|
with chatFrm do
|
|
begin
|
|
chat := TchatInfo.Create;
|
|
chat.who := nil;
|
|
chat.chatType := CT_PLUGING;
|
|
chat.single := singleDefault;
|
|
|
|
chat.lastInputText := TabCaption;
|
|
chats.Add(chat);
|
|
|
|
chat.ID := Control;
|
|
if not (iIcon = 0) then
|
|
theme.addHIco('plugintab' + IntToStr(chat.ID), iIcon, true);
|
|
ChatBox.OpenPage(chat.ID, TabCaption);
|
|
RedrawPluginTab(chat);
|
|
Resize;
|
|
saveListsDelayed := true;
|
|
RefreshTaskbarButtons;
|
|
|
|
Result := Integer(chatBox.Handle);
|
|
end;
|
|
end;
|
|
|
|
procedure CHAT_TAB_MODIFY(Control: Integer; iIcon: HIcon; const TabCaption: string);
|
|
var
|
|
chat: TchatInfo;
|
|
i: Integer;
|
|
begin
|
|
chat := nil;
|
|
for i := 0 to chatFrm.chats.count - 1 do
|
|
begin
|
|
if chatFrm.chats.byIdx(i).ID = Control then
|
|
begin
|
|
chat := chatFrm.chats.byIdx(i);
|
|
break;
|
|
end;
|
|
end;
|
|
if chat = nil then
|
|
Exit;
|
|
if not (iIcon = 0) then
|
|
theme.addHIco('plugintab' + IntToStr(chat.ID), iIcon, true);
|
|
|
|
// TchatInfo(chatFrm.chatTabs.Tabs[i].Data).ID = Control
|
|
// chatFrm.chatTabs.Tabs[i].Caption := TabCaption;
|
|
|
|
chat.lastInputText := TabCaption;
|
|
chatFrm.RedrawPluginTab(chat);
|
|
chatFrm.RefreshTaskbarButtons;
|
|
end;
|
|
|
|
procedure CHAT_TAB_DELETE(Control: Integer);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to chatFrm.chats.count - 1 do
|
|
begin
|
|
if chatFrm.chats.byIdx(i).ID = Control then
|
|
begin
|
|
chatFrm.ClosePageAt(i);
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TchatFrm.CreateParams(var Params: TCreateParams);
|
|
begin
|
|
inherited CreateParams(Params);
|
|
{ with Params do
|
|
begin
|
|
// Style := Style and (not WS_CAPTION);
|
|
// Style := Style and not WS_OVERLAPPEDWINDOW or WS_BORDER and (not WS_CAPTION);
|
|
// Style := (Style or WS_POPUP) and (not WS_DLGFRAME);
|
|
Style := Style or WS_SYSMENU;
|
|
ExStyle := ExStyle or WS_EX_APPWINDOW or WS_EX_NOPARENTNOTIFY;
|
|
end; }
|
|
end;
|
|
|
|
procedure TchatFrm.WMEXITSIZEMOVE(var Message: TMessage);
|
|
var
|
|
ch: TchatInfo;
|
|
begin
|
|
inherited;
|
|
ch := thisChat;
|
|
if ch = nil then
|
|
exit;
|
|
if ch.chatType = CT_PLUGING then
|
|
plugins.castEv(PE_SELECTTAB, ch.ID);
|
|
end;
|
|
|
|
procedure TchatFrm.closemenuPopup(Sender: TObject);
|
|
var
|
|
ch: TchatInfo;
|
|
begin
|
|
ch := thisChat;
|
|
if ch = nil then
|
|
exit;
|
|
// chatcloseignore1.visible:= ch.chatType <> CT_PLUGING;
|
|
// CloseallandAddtoIgnorelist1.visible:= ch.chatType <> CT_PLUGING;
|
|
end;
|
|
|
|
procedure TchatFrm.WMWINDOWPOSCHANGING(var msg: TWMWINDOWPOSCHANGING);
|
|
const
|
|
chkLeft = true;
|
|
chkRight = true;
|
|
chkTop = true;
|
|
chkBottom = true;
|
|
var
|
|
// rWorkArea: TRect;
|
|
rMainRect: TRect;
|
|
StickAt: Word;
|
|
begin
|
|
if Assigned(mainDlg.RnQmain) then
|
|
if mainDlg.RnQmain.visible then
|
|
begin
|
|
StickAt := 15; // StrToInt(edStickAt.Text);
|
|
rMainRect := mainDlg.RnQmain.BoundsRect;
|
|
// SystemParametersInfo
|
|
// (SPI_GETWORKAREA, 0, @rWorkArea, 0);
|
|
|
|
with msg.WindowPos^ do
|
|
begin
|
|
if chkLeft then
|
|
// if ABS(x - rWorkArea.Left) <= StickAt then begin
|
|
// x := rWorkArea.Left;
|
|
if (ABS(X - rMainRect.Right) <= StickAt) and (Y < rMainRect.Bottom) and (Y + cy > rMainRect.Top) then
|
|
X := rMainRect.Right;
|
|
|
|
if chkRight then
|
|
// if abs(x + cx - rWorkArea.Right) <= StickAt then begin
|
|
// x := rWorkArea.Right - cx;
|
|
if (ABS(X + cx - rMainRect.Left) <= StickAt) and (Y < rMainRect.Bottom) and (Y + cy > rMainRect.Top) then
|
|
X := rMainRect.Left - cx;
|
|
|
|
if chkTop then
|
|
if (ABS(Y - rMainRect.Bottom) <= StickAt) and (X < rMainRect.Right) and (X + cx > rMainRect.Left) then
|
|
Y := rMainRect.Bottom;
|
|
|
|
if chkBottom then
|
|
if (ABS(Y + cy - rMainRect.Top) <= StickAt) and (X < rMainRect.Right) and (X + cx > rMainRect.Left) then
|
|
Y := rMainRect.Top - cy;
|
|
end;
|
|
end;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TchatFrm.WMAppCommand(var msg: TMessage);
|
|
begin
|
|
case GET_APPCOMMAND_LPARAM(msg.LParam) of
|
|
APPCOMMAND_BROWSER_BACKWARD:
|
|
begin
|
|
ChatBox.SwitchToPrevPage;
|
|
msg.Result := 1;
|
|
end;
|
|
|
|
APPCOMMAND_BROWSER_FORWARD:
|
|
begin
|
|
ChatBox.SwitchToNextPage;
|
|
msg.Result := 1;
|
|
end;
|
|
|
|
APPCOMMAND_FIND, APPCOMMAND_BROWSER_SEARCH:
|
|
begin
|
|
showForm(WF_SEARCH);
|
|
msg.Result := 1;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TchatFrm.WMNCActivate(var msg: TWMNCActivate);
|
|
begin
|
|
inherited;
|
|
if Running and HandleAllocated then
|
|
ApplyTitleColors(msg.Active);
|
|
ApplyTransparency;
|
|
end;
|
|
|
|
procedure TchatFrm.DragDropFiles(var Message: TWMDropFiles);
|
|
var
|
|
ch: TchatInfo;
|
|
cnt: TICQContact;
|
|
i, n: Integer;
|
|
ss: String;
|
|
buffer: array [0 .. 2047] of Char;
|
|
begin
|
|
ch := thisChat;
|
|
if (ch = nil) then
|
|
Exit;
|
|
if ch.chatType = CT_IM then
|
|
begin
|
|
cnt := ch.who;
|
|
if cnt = nil then
|
|
Exit;
|
|
if cnt is TICQContact then
|
|
begin
|
|
ss := '';
|
|
n := DragQueryFile(Message.Drop, Cardinal(-1), nil, 0);
|
|
for i := 0 to n - 1 do
|
|
begin
|
|
DragQueryFile(Message.Drop, i, @buffer, sizeOf(buffer));
|
|
if i > 0 then
|
|
ss := ss + ';';
|
|
ss := ss + buffer;
|
|
end;
|
|
DragFinish(message.Drop);
|
|
if n > 0 then
|
|
ChatBox.AddToCurrentInput(ChatBox.FileUpload(n > 1, ss));
|
|
ss := '';
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TchatFrm.OnBeforeHeaderSend(Sender: TObject; const Method : String; Headers: TStrings);
|
|
begin
|
|
Headers.Add('Pragma: no-cache');
|
|
Headers.Add('Cache-Control: no-cache');
|
|
end;
|
|
|
|
procedure TchatFrm.OnSendData(Sender: TObject; Buffer: Pointer; Len: Integer);
|
|
begin
|
|
Inc(UploadedSize, Len);
|
|
if Assigned(chatFrm) and chatFrm.Visible then
|
|
SetStatusbar('');
|
|
end;
|
|
|
|
procedure TchatFrm.TaskBarThumbButtonClick(Sender: TObject; AButtonID: Integer);
|
|
begin
|
|
if AButtonID > chats.Count then
|
|
Exit;
|
|
SetCurrent(AButtonID);
|
|
Open(true);
|
|
end;
|
|
|
|
procedure TchatFrm.RefreshTaskbarButtons;
|
|
var
|
|
taskBtn: TThumbBarButton;
|
|
ci: TchatInfo;
|
|
hi: HICON;
|
|
i, cnt: Integer;
|
|
bmp: TRnQBitmap;
|
|
ev: Thevent;
|
|
begin
|
|
if not running then Exit;
|
|
if not CheckWin32Version(6, 1) then Exit;
|
|
if not Assigned(TaskBar.TaskBarButtons) then Exit;
|
|
|
|
cnt := Min(7, chats.Count);
|
|
|
|
TaskBar.TaskBarButtons.BeginUpdate;
|
|
for i := 0 to 6 do
|
|
begin
|
|
taskBtn := TaskBar.TaskBarButtons[i];
|
|
if Assigned(taskBtn.Icon) and taskBtn.Icon.HandleAllocated then
|
|
DestroyIcon(taskBtn.Icon.ReleaseHandle);
|
|
|
|
if (cnt = 0) or (i > cnt - 1) then
|
|
begin
|
|
taskBtn.Hint := '';
|
|
taskBtn.ButtonState := [TThumbButtonState.Hidden];
|
|
end
|
|
else
|
|
begin
|
|
taskBtn.ButtonState := [TThumbButtonState.Enabled, TThumbButtonState.DismissOnClick];
|
|
ci := TchatInfo(chats.byIdx(i));
|
|
if not Assigned(ci) then
|
|
Continue;
|
|
|
|
case ci.chatType of
|
|
CT_IM:
|
|
begin
|
|
if not (taskBtn.Hint = ci.who.displayed) then
|
|
taskBtn.Hint := ci.who.displayed;
|
|
|
|
ev := eventQ.firstEventFor(ci.who);
|
|
if (ev <> nil) then
|
|
begin
|
|
theme.pic2ico(RQteFormIcon, ev.pic, taskBtn.Icon);
|
|
Continue;
|
|
end;
|
|
end;
|
|
CT_PLUGING:
|
|
begin
|
|
if not (taskBtn.Hint = ci.lastInputText) then
|
|
taskBtn.Hint := ci.lastInputText;
|
|
|
|
theme.pic2ico(RQteFormIcon, 'plugintab' + IntToStr(ci.ID), taskBtn.Icon);
|
|
Continue;
|
|
end;
|
|
end;
|
|
|
|
if avatarShowInTaskBar and Assigned(ci.who.icon.Bmp) then
|
|
begin
|
|
if (ci.who.icon.Bmp.Animated) then
|
|
bmp := ci.who.icon.Bmp.CloneFrame(0)
|
|
else
|
|
bmp := ci.who.icon.Bmp.CloneAll;
|
|
|
|
StretchPic(bmp, 16, 16);
|
|
bmp.GetHICON(hi);
|
|
taskBtn.Icon.Handle := hi;
|
|
FreeAndNil(bmp);
|
|
end else
|
|
theme.pic2ico(RQteFormIcon, ci.who.statusImg, taskBtn.Icon);
|
|
end;
|
|
end;
|
|
TaskBar.TaskBarButtons.EndUpdate;
|
|
TaskBar.ApplyButtonsChanges;
|
|
end;
|
|
|
|
procedure TchatFrm.ApplyTitleColors(active: Boolean);
|
|
begin
|
|
if TOSVersion.Check(10) then
|
|
if Prevalence = 0 then
|
|
ChatBox.Call('setActiveStyle', [GetRValue(clWhite), GetGValue(clWhite), GetBValue(clWhite)])
|
|
else if active then
|
|
ChatBox.Call('setActiveStyle', [GetRValue(AccentColor), GetGValue(AccentColor), GetBValue(AccentColor)])
|
|
else
|
|
ChatBox.Call('setActiveStyle', [GetRValue(AccentColorInactive), GetGValue(AccentColorInactive), GetBValue(AccentColorInactive)])
|
|
end;
|
|
|
|
procedure TchatFrm.CMMouseEnter(var Msg: TMessage);
|
|
begin
|
|
if Pointer(Msg.LParam) = Pointer(ChatBox) then
|
|
if not FMouseInControl and transparency.chgOnMouse then
|
|
begin
|
|
if AlphaBlend then
|
|
AlphaBlendValue := transparency.active;
|
|
FMouseInControl := True;
|
|
end;
|
|
end;
|
|
|
|
procedure TchatFrm.CMMouseLeave(var Msg: TMessage);
|
|
begin
|
|
inherited;
|
|
if Pointer(Msg.LParam) = Pointer(ChatBox) then
|
|
if (transparency.chgOnMouse) and FMouseInControl then
|
|
begin
|
|
if AlphaBlend then
|
|
if Handle <> getForegroundWindow then
|
|
AlphaBlendValue := transparency.inactive;
|
|
FMouseInControl := False;
|
|
end;
|
|
end;
|
|
|
|
end.
|