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.
RnQ/RnQ/SciterLib.pas

1880 lines
59 KiB
Plaintext

{
This file is part of R&Q.
Under same license
}
unit SciterLib;
{$I RnQConfig.inc}
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, System.UITypes, System.StrUtils, System.Variants, System.TypInfo,
System.NetEncoding, Generics.Collections, Vcl.Graphics, Vcl.Forms, Vcl.Imaging.PNGImage, Vcl.Menus,
SciterJS, SciterJSAPI, RDGlobal, ICQCommon, ICQContacts, Nodes, CLBox, ChatBox, RQLog, RnQTips, PrefSheet, MainDlg, UtilLib;
{$I PubRTTI.inc}
type
TSCOptions = set of (sco_multi, sco_groups, sco_predefined);
TSprite = record
name: String;
x, y, width, height: Integer;
end;
TMessageStatus = record
when, msgid: String;
eventimg: Variant;
end;
TMessageHeader = record
when, caption, text, img: String;
end;
TContactStatus = record
code: Byte;
name, desc: String;
official, bot, deleted: Boolean;
statusimg, eventimg: Variant;
end;
TContactXStatus = record
status, text: String;
end;
TCommonSettings = record
supportAvatars, avatarShowInHint, avatarUsePalette, newSettings, animateWindows, animatedScroll, quitConfirmation, alertTopMost: Boolean;
end;
TNodeData = record
kind, group, divisor, order: Integer;
uid, uid2show: TUID;
hash, displayed, nick, first, last, birth, birthLocal, lastActivity,
clientClosed, clientDesc, onlineSince, lastTimeSeenOnline: String;
status, xstatus, clientimg, bdimg: Variant;
expanded, local, needAuth, hasAvatar, noClient: Boolean;
end;
{$I NoRTTI.inc}
TCommonMethods = class(TNativeMethods)
class procedure RegisterMethods(var ReturnValue: TSciterValue); override;
class procedure GetWindowCaptionHeight(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetTranslation(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetTranslations(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetSpriteData(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetImageBytes(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure CheckOnline(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure SetLargeWindowIcon(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetMaxPasswordLength(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetPwd(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetCurrentUserName(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetCurrentUserAcc(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetAccountPassword(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure SaveAccountPassword(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure IsAIM(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure HTMLDecode(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure ShowTaskbarButton(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure HideTaskbarButton(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure HideTaskbarButton2(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure SavePreviousWindow(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure ClearPreviousWindow(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure SwitchToPreviousWindow(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetContactIdle(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetContactImportant(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetContactIgnored(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetGroupName(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetContactData(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure SaveNewAccountPassword(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure CheckLockPassword(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure OpenLink(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure OpenPortal(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure IsOnline(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure IsElevated(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure IsWindows10(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure IsWindows8(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure ProcessMacro(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetUploadServerName(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetUpdateInfo(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetDoubleClickDelay(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetWeekDayByNumber(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetMonthNameByNumber(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure PrettyPrint(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
class procedure GetSystemAccentColors(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
end;
TSciterHelper = class helper for TSciter
function LoadTemplate(const Doc, Filename: String; Debug: Boolean = True): Boolean;
procedure InitRequest(ASender: TObject; const URL: WideString; ResType: SciterResourceType; RequestId: Pointer; out Discard: Boolean; out Delay: Boolean; out Myself: Boolean);
end;
TRequestHandler = class
private
FDataStream: TMemoryStream;
protected
procedure ProcessRequest(ASender: TObject; URL: WideString; ResType: SciterResourceType; RequestId: Pointer; out Discard: Boolean; out Delay: Boolean; out Myself: Boolean);
procedure CheckAnimatedGifSize(var ms: TMemoryStream);
public
constructor Create(Sender: TSciter);
destructor Destroy; override;
end;
TUI = class(TSciter)
private
ContactStatus: TContactStatus;
ContactXStatus: TContactXStatus;
StatusSprite, EventSprite, ClientSprite, BDSprite: TSprite;
public
CL: TContactList;
Chat: TChatBox;
Log: TLog;
Tips: TTips;
Prefs: TPrefs;
constructor Create;
procedure AppActivate(Sender: TObject);
procedure AppDeactivate(Sender: TObject);
procedure SystemSettingChange(Sender: TObject; Flag: Integer; const Section: string; var Result: Longint);
function GetNodeData(var Node: TNode; Lite: Boolean = False): TNodeData;
function IsVisible(Element: HELEMENT): Boolean;
function GetID(Element: HELEMENT): String;
function GetAttr(Element: HELEMENT; const AttrName: AnsiString): String;
function GetTag(Element: HELEMENT): String;
function CallOnElement(Element: HELEMENT; const FuncName: AnsiString; Params: TArray; IsMethod: Boolean = False): Variant;
procedure FireOnElement(Element: HELEMENT; const name: String; data: Variant; async: Boolean = True);
procedure CallInWindow(const WindowID, FuncName: AnsiString; Params: TArray = []);
procedure CreateCL;
procedure CreateChat;
procedure CreateLog;
procedure CreateTips;
procedure ApplySystemSettings;
function GetFocused(Window: HWINDOW): HELEMENT;
// function GetCurrentRoot: HELEMENT;
function GetImageColors(var str: TMemoryStream): TParams;
function EnterPassword(const Title: String; MaxLength: Integer = 0): String;
procedure EnterLockPassword(const Title, Hint: String; MaxLength: Integer = 0);
function CreateDialog(const Msg: String; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; Seconds: Integer): Integer;
procedure MessageDialog(const Msg: String; Kind: TMsgDlgType);
function InputQuery(const Caption, Text, Icon: String): String;
function SwitchUser(ShowConflictMsg: Boolean = False): TUID;
function SelectContacts(const Caption, Btn: String; Options: TSCOptions; CheckUID: TUID = ''): TParams;
procedure InitSettings;
procedure ReloadUsers;
procedure ViewInfo(UID: TUID; const Caption: String; UpdateOnly: Boolean = False);
procedure OpenPrefs(const Page: String = ''; Full: Boolean = True);
procedure OpenHistorySearch;
procedure OpenUpdater;
function OpenLangs(Langs: Variant): Integer;
procedure UpdateViewInfoAnP(UID: TUID);
procedure UpdateOutbox;
procedure UpdateDB;
procedure UpdateSessions(Current: Boolean = False);
procedure UpdateTranslations;
procedure CloseAllChildWindows;
procedure LoadData(ASender: TObject; const URL: WideString; ResType: SciterResourceType; RequestId: Pointer; out Discard, Delay, Myself: Boolean);
procedure ScriptingCall(ASender: TObject; const Args: TElementOnScriptingCallArgs);
end;
function GetWindowHandle(argc: UINT; argv: PSciterValue; Root: Boolean = True): HWND;
function MakeSprite(const Pic: TPicName): TSprite;
var
UI: TUI;
implementation
uses
System.JSON,
GlobalLib, GroupsLib, RoasterLib, IniLib, ThemesLib, RQUtil, RDUtils, Murmur2, litegif1,
RnQNet, RnQLangs, RnQGlobal, RnQGraphics32, RQThemes, RnQPics, RnQDialogs, RnQ_Avatars, RnQMacros, RnQSysUtils, Stickers,
ICQConsts, Protocol_ICQ, events, usersDlg, viewInfoDlg, aboutDlg, outboxDlg, RnQdbDlg, selectcontactsDlg,
HistAllSearch, StatusForm;
function LooksLikeALink(const link: String): Boolean;
begin
Result := StartsText('http://', link) or StartsText('https://', link) or StartsText('www.', link);
end;
{ TRequestHandler }
constructor TRequestHandler.Create(Sender: TSciter);
begin
FDataStream := nil;
end;
destructor TRequestHandler.Destroy;
begin
FreeAndNil(FDataStream);
inherited;
end;
procedure TRequestHandler.CheckAnimatedGifSize(var ms: TMemoryStream);
var
aGif: TGif;
sz: Single;
FStreamFormat: TPAFormat;
PNG: TPNGImage;
begin
FStreamFormat := DetectFileFormatStream(ms);
if (FStreamFormat = PA_FORMAT_GIF) then
begin
ms.Seek(0, soFromBeginning);
aGif := TGif.Create;
try
aGif.LoadFromStream(ms);
with aGif do
if ImageCount > 1 then
begin
sz := 4.85 * ImageCount * Width * Height / 1048576;
if sz > 50 then
try
ms.Clear;
PNG := TPNGImage.Create;
PNG.Assign(aGif.Bitmap[0]);
PNG.SaveToStream(ms);
PNG.Free;
ms.Seek(0, soFromBeginning);
except end;
end;
finally
aGif.Free;
end;
end;
end;
procedure TRequestHandler.ProcessRequest(ASender: TObject; URL: WideString; ResType: SciterResourceType; RequestId: Pointer; out Discard, Delay, Myself: Boolean);
var
Hash: LongWord;
Img: TBytes;
PNG: TPNGImage;
Ico: TIcon;
RealURL, FileURL, FileName, MurmurStr: String;
Mini: Boolean;
Pic: TPicName;
ResStream: TResourceStream;
StrStream: TStringStream;
Cached, IsImg, Check, Ignore, Async, HasAoP: Boolean;
FBox: TSciter;
Contact: TICQContact;
FileInfo: TICQFileInfo;
Pos: Integer;
begin
Ignore := False;
Async := False;
Myself := False;
FBox := ASender as TSciter;
if StartsText('file://', url) or StartsText('sciter:', url) then
if ContainsStr(url, 'url(') then // Some weird Sciter bug
begin
Pos := String(url).LastIndexOf('url(');
url := String(url).Substring(Pos + 4, Length(url) - Pos - 5);
end else
Exit;
FDataStream := nil;
// CSS reload fix
if StartsText('template:url(', url) then
url := Copy(url, 14, Length(url) - 14);
if StartsText('template:', url) then
begin
FDataStream := TMemoryStream.Create;
RealURL := Copy(url, 10, Length(url));
FBox.GetPackedItem('template', PWideChar(RealURL), FDataStream);
end else if StartsText('themeicon:', url) then
begin
RealURL := Copy(url, 11, Length(url));
Ico := TIcon.Create;
if theme.pic2ico(RQteDefault, RealURL, Ico) then
begin
FDataStream := TMemoryStream.Create;
Ico.SaveToStream(FDataStream)
end else
Ignore := True;
Ico.Free;
end else if StartsText('themepic:', url) then
begin
Pic := Copy(url, 10, Length(url));
if not theme.GetOrigPic(Pic, FDataStream) then
Ignore := True;
end else if StartsText('themepicsingle:', url) then
begin
RealURL := Copy(url, 16, Length(url));
if theme.Pic2PNG(RealURL, PNG) then
begin
FDataStream := TMemoryStream.Create;
PNG.SaveToStream(FDataStream)
end else
Ignore := True;
FreeAndNil(PNG);
end else if StartsText('pluginpic:', url) then
begin
Pic := Copy(url, 11, Length(url));
if theme.Pic2PNG(Pic, PNG) then
begin
FDataStream := TMemoryStream.Create;
PNG.SaveToStream(FDataStream);
end else
Ignore := True;
FreeAndNil(PNG);
end else if StartsText('contactpic:', url) and UseContactThemes and Assigned(ContactsTheme) then
begin
Pic := Copy(url, 12, Length(url));
if not ContactsTheme.GetOrigPic(Pic, FDataStream) then
Ignore := True;
end else if StartsText('smile:', url) then
begin
Pic := Copy(url, 7 + 1, Length(url));
if not theme.GetOrigSmile(Pic, FDataStream) then
Ignore := True;
end else if StartsText('sticker:', url) then
begin
RealURL := Copy(url, 9 + 1, Length(url));
TThread.CreateAnonymousThread(procedure
var
fs: TMemoryStream;
begin
fs := TMemoryStream.Create;
if String(url).startsWith('sticker:a') then
GetAnimatedSticker(RealURL, fs)
else
GetSticker(RealURL, fs);
if Assigned(FBox) and Running then
FBox.DataReadyAsync(url, fs.Memory, fs.Size, RequestId);
FreeAndNil(fs);
end).Start;
Delay := True;
Exit;
end else if StartsText('picker:', url) then
begin
RealURL := Copy(url, 8 + 1, Length(url));
TThread.CreateAnonymousThread(procedure
var
fs: TMemoryStream;
begin
fs := TMemoryStream.Create;
if String(url).startsWith('picker:a') then
GetAnimatedSticker(RealURL, fs, True)
else
GetSticker(RealURL, fs, 'stickerpicker_small');
if Assigned(FBox) and Running then
FBox.DataReadyAsync(url, fs.Memory, fs.Size, RequestId);
FreeAndNil(fs);
end).Start;
Delay := True;
Exit;
end else if StartsText('listicon:', url) then
begin
RealURL := Copy(url, 10 + 1, Length(url));
TThread.CreateAnonymousThread(procedure
var
fs: TMemoryStream;
begin
var
fn: String;
fs := TMemoryStream.Create;
fn := StickerPath + RealURL + '_listicon_small.webp';
if FileExists(fn) then
fs.LoadFromFile(fn);
if Assigned(FBox) and Running then
FBox.DataReadyAsync(url, fs.Memory, fs.Size, RequestId);
FreeAndNil(fs);
end).Start;
Delay := True;
Exit;
end else if StartsText('avatar:', url) or StartsText('miniavatar:', url) then
begin
Mini := StartsText('miniavatar:', url);
RealURL := Copy(url, IfThen(Mini, 12, 8), Length(url));
Contact := Account.AccProto.GetContact(RealURL);
if Contact.icon.ToShow = IS_AVATAR then
begin
FDataStream := TMemoryStream.Create;
LoadAoPStreamByUIN(Contact.UID, FDataStream, HasAoP, FileName, 0);
if Assigned(FDataStream) and (FDataStream.Size = 0) then
begin
FreeAndNil(FDataStream);
Ignore := True;
end;
if Mini and not Ignore then
ResampleProportional(FDataStream, 32, 32);
end else if Contact.icon.ToShow = IS_PHOTO then
begin
FDataStream := TMemoryStream.Create;
LoadAoPStreamByUIN(Contact.UID, FDataStream, HasAoP, FileName, 1);
if Assigned(FDataStream) and (FDataStream.Size = 0) then
begin
FreeAndNil(FDataStream);
Ignore := True;
end;
end else Ignore := True;
end else if StartsText('justavatar:', url) then
begin
RealURL := Copy(url, 12, Length(url));
Contact := Account.AccProto.GetContact(RealURL);
FDataStream := TMemoryStream.Create;
LoadAoPStreamByUIN(Contact.UID, FDataStream, HasAoP, FileName, 0);
if Assigned(FDataStream) and (FDataStream.Size = 0) then
begin
FreeAndNil(FDataStream);
Ignore := True;
end;
end else if StartsText('justphoto:', url) then
begin
RealURL := Copy(url, 11, Length(url));
Contact := Account.AccProto.GetContact(RealURL);
FDataStream := TMemoryStream.Create;
LoadAoPStreamByUIN(Contact.UID, FDataStream, HasAoP, FileName, 1);
if Assigned(FDataStream) and (FDataStream.Size = 0) then
begin
FreeAndNil(FDataStream);
Ignore := True;
end;
end else if StartsText('resource:', url) then
begin
RealURL := Copy(url, 10, Length(url));
ResStream := TResourceStream.Create(HInstance, UpperCase(RealURL), RT_RCDATA);
try
FDataStream := TMemoryStream.Create;
ResStream.SaveToStream(FDataStream);
finally
ResStream.Free;
end;
end else if StartsText('iconresource:', url) then
begin
RealURL := Copy(url, 14, Length(url));
ResStream := TResourceStream.Create(HInstance, UpperCase(RealURL), RT_ICON);
try
FDataStream := TMemoryStream.Create;
ResStream.SaveToStream(FDataStream);
finally
ResStream.Free;
end;
end else if StartsText('link:', url) then
begin
RealURL := ValidateURL(Copy(url, 6, Length(url)));
if ContainsText(RealURL, 'files.icq.net/') then
begin
if Account.AccProto.AimSid = '' then
FileInfo := GetICQFileLinkInfoPublic(RealURL)
else
FileInfo := GetICQFileLinkInfoPrivate(RealURL);
if FileInfo.dlink = '' then
FileURL := FileInfo.jsonlink
else
FileURL := FileInfo.dlink;
if not (FileURL = '') then
RealURL := FileURL;
end;
OpenURL(RealURL);
Ignore := True;
end else if StartsText('mailto:', url) then
begin
OpenURL(url);
Ignore := True;
end else if StartsText('embedded:', url) then
begin
if TryStrToLongWord(Copy(url, 10, Length(url)), Hash) and Assigned(EmbeddedImgs) and EmbeddedImgs.TryGetValue(Hash, Img) then
begin
FDataStream := TMemoryStream.Create;
FDataStream.Write(Img, Length(Img));
CheckAnimatedGifSize(FDataStream);
end;
end else if StartsText('tabicon:', url) then
begin
PNG := nil;
if TryStrToLongWord(Copy(url, 9, Length(url)), Hash) and Assigned(TabsIconCache) and TabsIconCache.TryGetValue(Hash, PNG) then
if Assigned(PNG) then
begin
FDataStream := TMemoryStream.Create;
PNG.SaveToStream(FDataStream)
end else
Ignore := True;
end else if StartsText('check:', url) or StartsText('download:', url) then
begin
if StartsText('check:', url) then
begin
Check := True;
RealURL := Copy(url, 7, Length(url));
end
else
begin
Check := False;
RealURL := Copy(url, 10, Length(url));
end;
if LooksLikeALink(RealURL) then
begin
MurmurStr := ImgCacheInfo.ReadString(RealURL, 'hash', '0');
FileName := myPath + 'Cache\Images\' + MurmurStr + '.' + ImgCacheInfo.ReadString(RealURL, 'ext', 'jpg');
if MurmurStr = '0' then
Cached := False
else
Cached := FileExists(FileName);
if not Check then
Async := True
else if Cached then
begin
IsImg := True;
Async := False;
end else if ImgCacheInfo.ValueExists(RealURL, 'mime') and not MatchText(ImgCacheInfo.ReadString(RealURL, 'mime', ''), ImageContentTypes) then
begin
IsImg := False;
Async := False;
end else
Async := True;
if not Async then
begin
StrStream := TStringStream.Create('{ "isImg": ' + IfThen(IsImg, '1', '0') + ', "isLottie": ' + IfThen(IsLottieMime(RealURL), '1', '0') + ', "link": "' + RealURL + '" }', TEncoding.UTF8);
FDataStream := TMemoryStream.Create;
FDataStream.CopyFrom(StrStream, 0);
StrStream.Free;
end;
end else
Ignore := True;
end else
begin
Discard := False;
Delay := False;
Exit;
end;
if not Ignore then
begin
if not Async then
begin
Delay := False;
FDataStream.Seek(0, soFromBeginning);
FBox.DataReady(url, FDataStream.Memory, FDataStream.Size);
end
else
begin
Myself := True;
RAPI.RequestUse(RequestId);
TThread.CreateAnonymousThread(procedure
var
ms: TMemoryStream;
fs: TFileStream;
ss: TStringStream;
begin
if Check then
begin
ss := TStringStream.Create('{ "isImg": ' + IfThen(CheckType(RealURL), '1', '0') + ', "isLottie": ' + IfThen(IsLottieMime(RealURL), '1', '0') + ', "link": "' + RealURL + '" }', TEncoding.UTF8);
TThread.Synchronize(nil, procedure begin
if Running then
begin
RAPI.RequestSetSucceeded(RequestId, 200, ss.Memory, ss.Size);
RAPI.RequestUnUse(RequestId);
end;
end);
FreeAndNil(ss);
Exit;
end;
fs := nil;
ms := nil;
if not Cached then
Cached := DownloadAndCache(RealURL);
if Cached then
try
FileName := myPath + 'Cache\Images\' + ImgCacheInfo.ReadString(RealURL, 'hash', '0') + '.' + ImgCacheInfo.ReadString(RealURL, 'ext', 'jpg');
fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
ms := TMemoryStream.Create;
ms.LoadFromStream(fs);
CheckAnimatedGifSize(ms);
TThread.Synchronize(nil, procedure begin
if not Running then
Exit;
RAPI.RequestSetSucceeded(RequestId, 200, ms.Memory, ms.Size);
RAPI.RequestUnUse(RequestId);
if Assigned(UI.Chat) then
UI.Chat.FinishImage(url);
if Assigned(PreviewChat) then
PreviewChat.FinishImage(url);
end);
except end else
TThread.Synchronize(nil, procedure()
begin
if not Running then
Exit;
RAPI.RequestSetFailed(RequestId, 404, nil, 0);
RAPI.RequestUnUse(RequestId);
end);
FreeAndNil(fs);
FreeAndNil(ms);
end).Start;
end;
Discard := False;
end else
Discard := True;
FreeAndNil(FDataStream);
end;
function MakeSprite(const Pic: TPicName): TSprite;
var
Rect: TGPRect;
begin
if (theme.token = 101) then
begin
Result.name := '';
Result.x := 0;
Result.y := 0;
Result.width := 0;
Result.height := 0;
Exit;
end;
Rect := theme.GetPicRect(RQteDefault, Pic);
Result.name := theme.GetPicSprite(RQteDefault, Pic);
Result.x := -rect.X;
Result.y := -rect.Y;
Result.width := rect.Width;
Result.height := rect.Height;
end;
{ TSciterEx }
function TUI.GetNodeData(var Node: TNode; Lite: Boolean = False): TNodeData;
var
LastActivity: TDateTime;
Group: TGroup;
Pic: String;
Event: Thevent;
begin
Result := Default(TNodeData);
if not Assigned(Node) then
Exit;
Result.divisor := Integer(Node.divisor);
Result.group := Node.groupId;
Result.kind := Node.kind;
Result.order := Node.order;
if Node.kind = NODE_DIV then
begin
case Node.divisor of
d_online: Result.order := 1;
d_nil: Result.order := 2;
d_recent: Result.order := 3;
d_offline: Result.order := 4;
d_contacts: Result.order := 5;
end;
end else if Node.kind = NODE_GROUP then
begin
Group := groups.Get(Node.groupId);
Result.displayed := Group.Name;
Result.expanded := Group.Expanded[Node.divisor];
Result.local := Group.IsLocal;
end else if Node.kind = NODE_CONTACT then
if Assigned(Node.contact) then
begin
Result.displayed := Node.contact.Displayed;
Result.uid := Node.contact.UID;
Result.uid2show := Node.contact.UIN2Show;
Result.nick := Node.contact.Nick;
Result.first := Node.contact.First;
Result.last := Node.contact.Last;
Result.birth := IfThen(Node.contact.Birth = 0, '', FormatDateTime('DD.MM.YYYY', Node.contact.Birth));
Result.birthLocal := IfThen(Node.contact.BirthL = 0, '', FormatDateTime('DD.MM.YYYY', Node.contact.BirthL));
Result.needAuth := not Node.contact.Authorized and not Node.contact.CntIsLocal;
Result.local := Node.contact.CntIsLocal;
Result.noClient := Node.contact.NoClient;
Result.clientClosed := TimeToString(Node.contact.ClientClosed);
Result.clientDesc := Node.contact.ClientDesc;
Result.onlineSince := TimeToString(Node.contact.OnlineSince);
Result.lastTimeSeenOnline := TimeToString(Node.contact.LastTimeSeenOnline);
if Lite then
Exit;
LastActivity := TCE(Node.contact.data^).lastMsgTime;
if LastActivity < StartTime then
// if not Node.contact.IsOnline then
begin
LastActivity := TCE(Node.contact.data^).lastEventTime;
if LastActivity < StartTime then
LastActivity := 0;
end;
Result.lastActivity := FloatToStr(LastActivity);
Result.hasAvatar := CheckAvatar(Node.contact);
// Status
Pic := RosterImgNameFor(Node.contact);
if Pic = '' then
Exit;
ContactStatus.official := Node.contact.Official;
ContactStatus.bot := Node.contact.Bot;
ContactStatus.deleted := Node.contact.Deleted;
ContactStatus.code := Node.contact.GetStatus;
ContactStatus.desc := Node.contact.StatusStr;
ContactStatus.name := Node.contact.GetStatusName;
StatusSprite := MakeSprite(Pic);
ContactStatus.statusimg := RecordToVar(StatusSprite);
Event := eventQ.firstEventFor(Node.contact);
if Assigned(Event) and not (Event.pic = '') then
begin
EventSprite := MakeSprite(Event.pic);
ContactStatus.eventimg := RecordToVar(EventSprite);
end else
ContactStatus.eventimg := False;
Result.status := RecordToVar(ContactStatus);
ContactXStatus.status := Node.contact.XStatus;
ContactXStatus.text := XStatus2Text(ContactXStatus.status);
Result.xstatus := RecordToVar(ContactXStatus);
// Client
if not (Node.contact.ClientPic = '') then
begin
ClientSprite := MakeSprite(Node.contact.ClientPic);
Result.clientimg := RecordToVar(ClientSprite);
end else
Result.clientimg := False;
// Birthday
case Node.contact.Days2Bd of
0: Pic := PIC_BIRTH;
1: Pic := PIC_BIRTH1;
2: Pic := PIC_BIRTH2;
else
Pic := '';
end;
if not (Pic = '') then
begin
BDSprite := MakeSprite(Pic);
Result.bdimg := RecordToVar(BDSprite);
end else
Result.bdimg := False;
end;
Result.hash := IntToStr(CalcMurmur2(TEncoding.UTF8.GetBytes(IntToStr(Result.kind) + '_' + IntToStr(Result.divisor) + '_' + IntToStr(Result.group) + '_' + String(Result.uid))));
// if Result.kind = NODE_GROUP then
// ODS('Group node: ' + inttostr(Result.group) + ' ' + Result.displayed + ' | ' + Result.hash);
end;
function TUI.IsVisible(Element: HELEMENT): Boolean;
var
pResult: LongBool;
begin
API.SciterIsElementVisible(Element, pResult);
Result := pResult;
end;
function TUI.GetID(Element: HELEMENT): String;
begin
Result := GetAttr(Element, 'id');
end;
procedure GetTextCallback(str: PWideChar; str_length: UINT; param: Pointer); stdcall;
begin
if not (str = nil) and not (str_length = 0) then
String(param^) := String(str);
end;
function TUI.GetAttr(Element: HELEMENT; const AttrName: AnsiString): String;
begin
Result := '';
if AttrName = '' then
Exit;
API.SciterGetAttributeByNameCB(Element, PAnsiChar(AttrName), PLPCWSTR_RECEIVER(@GetTextCallback), @Result);
end;
function TUI.GetTag(Element: HELEMENT): String;
begin
API.SciterGetElementTypeCB(Element, PLPCSTR_RECEIVER(@GetTextCallback), @Result);
end;
{ TSciterHelper }
function TSciterHelper.LoadTemplate(const Doc, Filename: String; Debug: Boolean = True): Boolean;
begin
SetOption(SCITER_SET_SCRIPT_RUNTIME_FEATURES, UINT_PTR(ALLOW_FILE_IO) or UINT_PTR(ALLOW_SOCKET_IO) or UINT_PTR(ALLOW_EVAL) or UINT_PTR(ALLOW_SYSINFO));
SetOption(SCITER_SET_PX_AS_DIP, UINT_PTR(False));
SetOption(SCITER_SET_DEBUG_MODE, UINT_PTR(DevMode and Debug));
if DevMode then
Result := LoadURL(FilePathToURL(myPath + Doc + '\' + Filename))
else if FileExists(myPath + Doc + '.zip') then
Result := LoadURL(FilePathToURL(myPath + Doc + '.zip#' + Filename))
else
begin
LoadPackedResource(Doc, RT_RCDATA);
Result := LoadURL(Doc + ':' + Filename);
end;
end;
procedure TSciterHelper.InitRequest(ASender: TObject; const URL: WideString; ResType: SciterResourceType; RequestId: Pointer; out Discard, Delay, Myself: Boolean);
var
handler: TRequestHandler;
begin
handler := TRequestHandler.Create(Self);
handler.ProcessRequest(ASender, URL, ResType, RequestId, Discard, Delay, Myself);
handler.Free;
end;
// Native methods
class procedure TCommonMethods.GetSpriteData(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
str: String;
Sprite: TSprite;
begin
if argc = 0 then
Exit;
str := SciterVarToString(argv);
if str = '' then
Exit;
with UI do
begin
Sprite := MakeSprite(str);
V2S(RecordToVar(Sprite), retval);
end;
end;
class procedure TCommonMethods.GetImageBytes(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
URL, RealURL: String;
PNG: TPNGImage;
Bytes: TBytesStream;
begin
URL := SciterVarToString(argv);
RealURL := '';
if StartsText('themepicsingle:', URL) then
RealURL := Copy(URL, 16, Length(URL));
if RealURL = '' then
Exit;
if theme.Pic2PNG(RealURL, PNG) then
begin
Bytes := TBytesStream.Create;
PNG.SaveToStream(Bytes);
V2S(Bytes.Bytes, retval);
Bytes.Free;
end;
FreeAndNil(PNG);
end;
class procedure TCommonMethods.GetTranslation(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
strData: String;
begin
if argc = 0 then
Exit;
strData := SciterVarToString(argv);
strData := RnQLangs.GetTranslation(strData);
API.ValueStringDataSet(retval, PWideChar(strData), Length(strData), 0);
end;
function EnumParams(param: Pointer; const pkey: PSciterValue; const pval: PSciterValue): BOOL; stdcall;
var
key, val: String;
newval: TSciterValue;
begin
Result := True;
key := SciterVarToString(pval);
if key = '' then
Exit;
val := SciterVarToString(pval);
val := GetTranslation(val);
API.ValueInit(@newval);
API.ValueStringDataSet(@newval, PWideChar(val), Length(val), 0);
API.ValueSetValueToKey(param, pkey, @newval);
API.ValueClear(@newval);
end;
class procedure TCommonMethods.GetTranslations(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
arrSize, i: UINT;
strData: PWideChar;
strLen: UINT;
val: TSciterValue;
begin
if argc = 0 then
Exit;
if argv.t = UINT(T_OBJECT) then
if argv.u = UINT(UT_OBJECT_OBJECT) then
API.ValueEnumElements(argv, @EnumParams, retval)
else if argv.u = UINT(UT_OBJECT_ARRAY) then
begin
arrSize := 0;
API.ValueIsolate(argv);
API.ValueElementsCount(argv, arrSize);
for i := 0 to arrSize - 1 do
begin
API.ValueInit(@val);
if API.ValueNthElementValue(argv, i, val) = HV_OK then
begin
API.ValueStringData(@val, strData, strLen);
strData := PWideChar(RnQLangs.GetTranslation(strData));
API.ValueStringDataSet(@val, strData, Length(strData), 0);
API.ValueNthElementValueSet(retval, i, @val)
end;
API.ValueClear(@val);
end;
end;
end;
class procedure TCommonMethods.CheckOnline(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
res: Boolean;
begin
res := OnlFeature(Account.AccProto);
API.ValueIntDataSet(retval, RDUtils.IfThen(res, 1), T_BOOL, 0);
end;
class procedure TCommonMethods.SetLargeWindowIcon(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
Hndl: HWND;
HIco: HIcon;
Pic: String;
begin
Hndl := GetWindowHandle(argc, argv);
if Hndl <= 0 then
Exit;
Inc(argv);
Pic := SciterVarToString(argv);
try
if (Pic = '') or (Pic = '-') then
HIco := Application.Icon.Handle
else
HIco := LoadIcon(HInstance, PWideChar(Pic));
SendMessage(Hndl, WM_SETICON, ICON_BIG, HIco);
if Pic = '-' then
begin
SendMessage(Hndl, WM_SETICON, ICON_SMALL, 0);
// SetWindowLong(Hndl, GWL_EXSTYLE, GetWindowLong(Hndl, GWL_EXSTYLE) or WS_EX_DLGMODALFRAME);
// SetWindowPos(Hndl, 0, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER or SWP_FRAMECHANGED or SWP_NOACTIVATE);
end;
except end;
end;
class procedure TCommonMethods.GetMaxPasswordLength(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
V2S(Account.AccProto._MaxPwdLen, retval);
end;
class procedure TCommonMethods.GetPwd(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
V2S(Account.AccProto.Pwd, retval);
end;
class procedure TCommonMethods.GetContactIdle(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
UIN: TUID;
IdleTime: Integer;
Contact: TICQContact;
begin
Contact := nil;
IdleTime := 0;
UIN := SciterVarToString(argv);
if not (UIN = '') then
Contact := Account.AccProto.GetContact(UIN);
if Assigned(Contact) then
IdleTime := Contact.IdleTime;
V2S(IdleTime, retval);
end;
class procedure TCommonMethods.GetContactImportant(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
UIN: TUID;
Important: String;
Tmp: Integer;
GetLocal: Boolean;
Contact: TICQContact;
begin
Contact := nil;
Important := '';
UIN := SciterVarToString(argv);
if not (UIN = '') then
Contact := Account.AccProto.GetContact(UIN);
Inc(argv);
Tmp := 0;
API.ValueIntData(argv, Tmp);
GetLocal := Tmp = 1;
if Assigned(Contact) then
Important := IfThen(GetLocal, Contact.lclImportant, Contact.ssImportant);
V2S(Important, retval);
end;
class procedure TCommonMethods.GetContactIgnored(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
UIN: TUID;
Contact: TICQContact;
Ignored: Boolean;
begin
Contact := nil;
Ignored := False;
UIN := SciterVarToString(argv);
if not (UIN = '') then
Contact := Account.AccProto.GetContact(UIN);
if Assigned(Contact) then
Ignored := Contact.IsInList(LT_SPAM) or IgnoreList.exists(Contact);
V2S(Ignored, retval);
end;
class procedure TCommonMethods.GetCurrentUserName(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
V2S(RnQUser, retval);
end;
class procedure TCommonMethods.GetGroupName(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
Group: Integer;
begin
Group := 0;
API.ValueIntData(argv, Group);
if Group = 0 then
V2S('', retval)
else
V2S(groups.ID2Name(Group), retval);
end;
class procedure TCommonMethods.GetContactData(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
UIN: TUID;
Contact: TICQContact;
NodeData: TNodeData;
begin
Contact := nil;
UIN := SciterVarToString(argv);
if not (UIN = '') then
Contact := Account.AccProto.GetContact(UIN);
if not Assigned(Contact) then
begin
V2S(varNull, retval);
Exit;
end;
with UI do
begin
if TCE(Contact.Data^).Node = nil then
TCE(Contact.Data^).Node := TNode.Create(d_nil, Contact);
NodeData := GetNodeData(TCE(Contact.Data^).Node);
V2S(RecordToVar(NodeData), retval);
end;
end;
class procedure TCommonMethods.GetCurrentUserAcc(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
V2S(Account.AccProto.MyAccNum, retval);
end;
class procedure TCommonMethods.GetAccountPassword(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
V2S(AccPass, retval);
end;
class procedure TCommonMethods.SaveAccountPassword(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
if argc = 0 then
Exit;
if UpdateAccountEncryption(SciterVarToString(argv)) then
ActionManager.Execute(AK_SAVECONFIG, SaveDelay);
end;
class procedure TCommonMethods.SaveNewAccountPassword(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
if argc > 0 then
NewAccPass := SciterVarToString(argv);
end;
class procedure TCommonMethods.CheckLockPassword(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
Pwd: String;
begin
if argc = 0 then
Exit;
Pwd := SciterVarToString(argv);
if not (AccPass = '') then
V2S(CompareText(AccPass, Pwd) = 0, retval)
else
V2S(Account.AccProto.PwdEqual(Pwd), retval);
end;
class procedure TCommonMethods.OpenLink(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
URL: String;
begin
URL := SciterVarToString(argv);
if not (URL = '') then
OpenURL(URL);
end;
class procedure TCommonMethods.OpenPortal(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
OpenURL(rnqSite)
end;
class procedure TCommonMethods.IsOnline(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
V2S(Assigned(Account.AccProto) and Account.AccProto.IsOnline, retval)
end;
class procedure TCommonMethods.IsAIM(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
MyInf: TICQContact;
IsAIM: Boolean;
begin
IsAIM := False;
if not Assigned(Account.AccProto) then
Exit;
MyInf := Account.AccProto.GetMyInfo;
if Assigned(MyInf) then
IsAIM := MyInf.isAIM;
V2S(IsAIM, retval);
end;
class procedure TCommonMethods.IsElevated(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
V2S(utilLib.IsElevated, retval);
end;
class procedure TCommonMethods.IsWindows10(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
V2S(IsTen, retval);
end;
class procedure TCommonMethods.IsWindows8(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
V2S(IsEight, retval);
end;
class procedure TCommonMethods.ProcessMacro(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
I, Key: Integer;
Shift: TShiftState;
function Match(Shortcut: TShortcut): Boolean;
var
HK: Word;
State: TShiftState;
begin
ShortCutToKey(Shortcut, HK, State);
if ShortCut and scCommand <> 0 then Include(State, ssCommand); // WIN key
Result := ((HK and not scCommand) = Key) and (State = Shift);
end;
begin
Key := 0;
API.ValueIntData(argv, Key);
Shift := [];
Inc(argv);
I := 0;
API.ValueIntData(argv, I);
if I = 1 then
Shift := Shift + [ssShift];
Inc(argv);
I := 0;
API.ValueIntData(argv, I);
if I = 1 then
Shift := Shift + [ssCtrl];
Inc(argv);
I := 0;
API.ValueIntData(argv, I);
if I = 1 then
Shift := Shift + [ssAlt];
Inc(argv);
I := 0;
API.ValueIntData(argv, I);
if I = 1 then
Shift := Shift + [ssCommand];
if HotkeysEnabled and (Key > 0) then
for I := Low(Macros) to High(Macros) do
if not Macros[I].sw and Match(Macros[i].hk) then
ExecuteMacro(Macros[i].opcode);
end;
class procedure TCommonMethods.GetUploadServerName(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
if ServerToUpload = 0 then
V2S('files.icq.net', retval)
else if ServerToUpload = 1 then
V2S('code.highspec.ru', retval)
else
V2S('rnq.ru', retval);
end;
class procedure TCommonMethods.GetUpdateInfo(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
UpdateInfo: TUpdateInfo;
begin
CheckUpdates(UpdateInfo);
V2S(UI.RecordToVar(UpdateInfo), retval);
end;
class procedure TCommonMethods.GetDoubleClickDelay(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
V2S(GetDoubleClickTime, retval);
end;
class procedure TCommonMethods.GetWindowCaptionHeight(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
Height: Integer;
begin
Height := GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CXPADDEDBORDER) * 2 + GetSystemMetrics(SM_CYFRAME) * 2;
V2S(Height, retval);
end;
class procedure TCommonMethods.GetWeekDayByNumber(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
Num: Integer;
WeekDay: String;
begin
Num := 0;
API.ValueIntData(argv, Num);
WeekDay := GetWeekDay(Num);
V2S(WeekDay, retval);
end;
class procedure TCommonMethods.GetMonthNameByNumber(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
Num: Integer;
MonthName: String;
begin
Num := 0;
API.ValueIntData(argv, Num);
MonthName := GetGenitiveMonthName(Num);
V2S(MonthName, retval);
end;
class procedure TCommonMethods.PrettyPrint(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
Text: String;
begin
Text := PrettyPrintJSON(TJSONValue.ParseJSONValue(SciterVarToString(argv)));
V2S(Text, retval);
end;
class procedure TCommonMethods.GetSystemAccentColors(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
AccentColors: TArray;
begin
AccentColors := [GetRValue(AccentColor), GetGValue(AccentColor), GetBValue(AccentColor), Byte(AccentColor shr 24)];
V2S(AccentColors, retval);
end;
function GetWindowHandle(argc: UINT; argv: PSciterValue; Root: Boolean = True): HWND;
var
B: PByte;
Pb: Cardinal;
PResult: HELEMENT;
Hndl: HWND;
begin
B := nil;
Hndl := 0;
if (argc > 0) then
if argv.t = UINT(T_RESOURCE) then
begin
API.SciterElementUnwrap(argv, PResult);
if Assigned(PResult) then
API.SciterGetElementHwnd(PResult, Hndl, Root);
end else if (argv.t = UINT(T_OBJECT)) and (argv.u = UINT(UT_OBJECT_NATIVE)) then
begin
API.ValueBinaryData(argv, B, Pb);
if Assigned(B) then
API.SciterGetElementHwnd(B, Hndl, Root);
end;
Result := Hndl;
end;
//procedure TCommonMethods.ActivateWindow(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
//var
// Hndl: HWND;
//begin
// Hndl := GetWindowHandle(argc, argv);
// if Hndl > 0 then
// SetForegroundWindow(Hndl);
//end;
//procedure TCommonMethods.IsWindowActive(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
//var
// Hndl, Forg: HWND;
//begin
// Hndl := GetWindowHandle(argc, argv);
// Forg := GetForegroundWindow;
// if Hndl > 0 then
// V2S((Forg = Hndl) or (Forg = GetParent(Hndl)), retval)
// else
// V2S(False, retval)
//end;
procedure SetupWindowTask(Window: HWND; ShowButton: Boolean; WindowType: Integer = 0);
var
ExStyle: Integer;
begin
if Window = 0 then
Exit;
ExStyle := GetWindowLongPtr(Window, GWL_EXSTYLE);
if ShowButton then
ExStyle := ExStyle or WS_EX_APPWINDOW
else
ExStyle := ExStyle and not WS_EX_APPWINDOW;
if WindowType > 0 then
ExStyle := ExStyle or WindowType;
SetWindowLongPtr(Window, GWL_EXSTYLE, ExStyle);
end;
class procedure TCommonMethods.ShowTaskbarButton(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
SetupWindowTask(GetWindowHandle(argc, argv), True);
end;
class procedure TCommonMethods.HideTaskbarButton(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
SetupWindowTask(GetWindowHandle(argc, argv), False);
end;
class procedure TCommonMethods.HideTaskbarButton2(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
SetupWindowTask(GetWindowHandle(argc, argv), False, WS_EX_NOACTIVATE);
end;
//procedure SetDesktopAsParent(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
//var
// Window: HWND;
//begin
// Window := GetWindowHandle(argc, argv, False);
// SetParent(Window, 0);
// SetWindowLongPtr(Window, GWLP_HWNDPARENT, 0);
//end;
class procedure TCommonMethods.SavePreviousWindow(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
PrevWnd := GetForegroundWindow;
end;
class procedure TCommonMethods.ClearPreviousWindow(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
PrevWnd := 0;
end;
class procedure TCommonMethods.SwitchToPreviousWindow(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
begin
if PrevWnd > 0 then
begin
SetForegroundWindow(PrevWnd);
PrevWnd := 0;
end;
end;
class procedure TCommonMethods.HTMLDecode(argc: UINT; argv: PSciterValue; retval: PSciterValue); cdecl;
var
Text: String;
begin
Text := THTMLEncoding.HTML.Decode(SciterVarToString(argv));
V2S(Text, retval);
end;
// TUI
constructor TUI.Create;
begin
inherited Create;
OnLoadData := LoadData;
OnScriptingCall := ScriptingCall;
end;
procedure TUI.CreateCL;
begin
CL := TContactList.Create;
CL.Root := HELEMENT(NativeInt(Call('createContactList')));
API.SciterGetElementHwnd(CL.Root, CL.Window, True);
if CL.Window = 0 then
raise ESciterException.Create('Cannot get CL window handle');
// Hide close button
// SetWindowLongPtr(CL.Window, GWL_STYLE, GetWindowLongPtr(CL.Window, GWL_STYLE) and not WS_SYSMENU);
// Remove icon and hide taskbar button
//SetupWindowTask(CL.Window, False, WS_EX_DLGMODALFRAME);
LastMonCnt := GetActiveMonitorCount;
CL.SavePositionForCurrentMonitorCount;
end;
procedure TUI.CreateChat;
begin
Chat := TChatBox.Create;
Chat.Root := HELEMENT(NativeInt(Call('createChat')));
API.SciterGetElementHwnd(Chat.Root, Chat.Window, True);
if Chat.Window = 0 then
raise ESciterException.Create('Cannot get chat window handle');
// Do not repaint under child windows (plugin tabs)
SetWindowLongPtr(Chat.Window, GWL_STYLE, GetWindowLongPtr(Chat.Window, GWL_STYLE) or WS_CLIPCHILDREN);
end;
procedure TUI.CreateLog;
begin
Log := TLog.Create;
Log.Root := HELEMENT(NativeInt(Call('createLog')));
API.SciterGetElementHwnd(Log.Root, Log.Window, True);
if Log.Window = 0 then
raise ESciterException.Create('Cannot get log window handle');
end;
procedure TUI.CreateTips;
begin
Tips := TTips.Create;
Tips.Root := HELEMENT(NativeInt(Call('createTips')));
API.SciterGetElementHwnd(Tips.Root, Tips.Window, True);
if Tips.Window = 0 then
raise ESciterException.Create('Cannot get tips window handle');
Tips.InitWndProc;
SetupWindowTask(Tips.Window, False, WS_EX_NOACTIVATE);
end;
function TUI.CallOnElement(Element: HELEMENT; const FuncName: AnsiString; Params: TArray; IsMethod: Boolean = False): Variant;
var
RetVal: TSciterValue;
Handle: HWINDOW;
Res: SCDOM_RESULT;
begin
Result := Unassigned;
if Element = nil then Exit;
Res := API.SciterGetElementHwnd(Element, Handle, True);
if Res <> SCDOM_OK then
begin
ODS('CallOnElement failed: [' + FuncName + '] ' + IntToStr(Integer(res)));
Exit;
end;
if Handle = 0 then
begin
ODS('CallOnElement failed: handle is zero');
Exit;
end;
API.ValueInit(@RetVal);
if IsMethod then
begin
if (CallScriptMethod(Element, FuncName, Params, RetVal) = SCDOM_OK) then
S2V(@RetVal, Result, FuncName)
end else if (CallScriptFunction(Element, FuncName, Params, RetVal) = SCDOM_OK) then
S2V(@RetVal, Result, FuncName);
API.ValueClear(@RetVal);
end;
procedure TUI.FireOnElement(Element: HELEMENT; const name: String; data: Variant; async: Boolean = True);
begin
FireCustom(Element, name, data, async);
end;
procedure TUI.CallInWindow(const WindowID, FuncName: AnsiString; Params: TArray = []);
var
Doc: HELEMENT;
Res: Variant;
begin
Res := Call('findWindowDocument', [WindowID]);
if not VarIsNumeric(Res) or VarIsClear(Res) or VarIsEmpty(Res) or VarIsNull(Res) or (VarCompareValue(Res, Unassigned) = vrEqual) then
Exit;
Doc := Pointer(NativeInt(Res));
if Assigned(Doc) then
UI.CallOnElement(Doc, FuncName, Params);
end;
procedure TUI.MessageDialog(const Msg: String; Kind: TMsgDlgType);
begin
Call('showAlert', [Kind, Msg, False]);
end;
function TUI.InputQuery(const Caption, Text, Icon: String): String;
begin
Result := Call('inputQuery', [Caption, Text, Icon]);
end;
function TUI.GetFocused(Window: HWINDOW): HELEMENT;
begin
if not (API.SciterGetFocusElement(Window, Result) = SCDOM_OK) then
Result := nil;
end;
//function TUI.GetCurrentRoot: HELEMENT;
//begin
// if not (API.SciterGetRootElement(GetForegroundWindow, Result) = SCDOM_OK) then
// Result := nil;
//end;
procedure TUI.AppActivate(Sender: TObject);
begin
InactiveTime := 0;
if Assigned(UI) and Assigned(UI.Tips) then
UI.Tips.Reposition;
if Assigned(Account.AccProto) then
Account.AccProto.CheckEventSubscribe(6);
end;
procedure TUI.AppDeactivate(Sender: TObject);
begin
InactiveTime := 0;
CheckTopMost;
end;
procedure TUI.SystemSettingChange(Sender: TObject; Flag: Integer; const Section: string; var Result: Longint);
begin
case Flag of
SPI_SETMENUANIMATION, SPI_SETTOOLTIPANIMATION, SPI_SETSELECTIONFADE:
ApplySystemSettings;
end;
end;
procedure TUI.ApplySystemSettings;
var
AccentColors: TArray;
AccentInactiveColors: TArray;
begin
if UIAccentColor = 1 then
AccentColors := [GetRValue(UIAccentColorVal), GetGValue(UIAccentColorVal), GetBValue(UIAccentColorVal), 255]
else
AccentColors := [GetRValue(AccentColor), GetGValue(AccentColor), GetBValue(AccentColor), Byte(AccentColor shr 24)];
AccentInactiveColors := [GetRValue(AccentColorInactive), GetGValue(AccentColorInactive), GetBValue(AccentColorInactive), Byte(AccentColorInactive shr 24)];
Call('setSystemSettings', [AccentColors, AccentInactiveColors, MenuFadeEnabled, TooltipFadeEnabled, SelectionFadeEnabled]);
end;
function TUI.GetImageColors(var str: TMemoryStream): TParams;
var
img: Variant;
buf: Pointer;
// Freq, StartCount, StopCount: Int64;
// TimingSeconds: real;
begin
img := VarArrayCreate([0, str.Size - 1], varByte);
buf := VarArrayLock(img);
str.Seek(0, soFromBeginning);
str.ReadBuffer(buf^, str.Size);
VarArrayUnlock(img);
//QueryPerformanceFrequency(Freq);
//QueryPerformanceCounter(StartCount);
Result := Call('getImageColors', [img]);
//QueryPerformanceCounter(StopCount);
//TimingSeconds := (StopCount - StartCount) / Freq;
//ODS('Vibrant run: ' + floattostr(TimingSeconds));
end;
function TUI.EnterPassword(const Title: String; MaxLength: Integer = 0): String;
begin
Result := Call('enterPassword', [Title, MaxLength]);
end;
procedure TUI.EnterLockPassword(const Title, Hint: String; MaxLength: Integer = 0);
begin
Call('enterLockPassword', [Title, Hint, MaxLength]);
end;
function TUI.SwitchUser(ShowConflictMsg: Boolean = False): TUID;
begin
Result := Call('switchUser', [ShowConflictMsg]);
end;
function TUI.SelectContacts(const Caption, Btn: String; Options: TSCOptions; CheckUID: TUID = ''): TParams;
begin
Result := Call('openUINList', [Caption, Btn, Byte(Options), CheckUID]);
end;
procedure TUI.ReloadUsers;
begin
CallInWindow('users', 'reloadUsers');
end;
procedure TUI.ViewInfo(UID: TUID; const Caption: String; UpdateOnly: Boolean = False);
begin
Call('openViewInfo', [UID, Caption, UpdateOnly]);
end;
procedure TUI.OpenPrefs(const Page: String = ''; Full: Boolean = True);
begin
Call('openPrefs', [Page, Full]);
end;
procedure TUI.OpenHistorySearch;
begin
Call('openHistorySearch');
end;
procedure TUI.OpenUpdater;
begin
Call('openUpdater');
end;
function TUI.OpenLangs(Langs: Variant): Integer;
begin
Result := Call('openLangs', [Langs]);
end;
procedure TUI.UpdateViewInfoAnP(UID: TUID);
begin
CallInWindow('info:' + UID, 'updateAvatarAndPhoto');
end;
procedure TUI.UpdateOutbox;
begin
CallInWindow('outbox', 'updateList', [true]);
CallInWindow('outbox', 'updateText');
end;
procedure TUI.UpdateDB;
begin
CallInWindow('db', 'updateList');
end;
procedure TUI.UpdateSessions(Current: Boolean = False);
begin
CallInWindow('sessionsmgr', IfThen(Current, 'removeCurrent', 'updateSessionsList'));
end;
procedure TUI.UpdateTranslations;
begin
if Assigned(UI.CL) then
begin
UI.CL.UpdateTranslation;
UI.CL.InitMenus;
UI.CL.UpdateAdditionalImage;
UI.CL.UpdateVisibilityImage;
RebuildCL;
end;
if Assigned(UI.Chat) then
begin
UI.Chat.UpdateTranslation;
UI.Chat.UpdateHintsTraslation;
end;
if Assigned(UI.Log) then
UI.Log.UpdateTranslation;
end;
procedure TUI.CloseAllChildWindows;
begin
Call('closeChildWindows');
end;
function TUI.CreateDialog(const Msg: String; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; Seconds: Integer): Integer;
var
DefaultButton, CancelButton: TMsgDlgBtn;
DefaultButtonVar, CancelButtonVar: Variant;
ButtonsVar: TParams;
Title, Icon, ResultBtn: String;
begin
case DlgType of
mtWarning:
Icon := PIC_EXCLAMATION;
mtError:
Icon := PIC_HAND;
mtInformation:
Icon := PIC_ASTERISK;
mtConfirmation:
Icon := PIC_QUEST;
mtBuzz:
Icon := PIC_BUZZ;
mtCustom:
Icon := '';
end;
if DlgType <> mtCustom then
Title := GetTranslation(LoadResString(Captions[DlgType]))
else
Title := Application.Title;
if RnQUser > '' then
Title := Title + ' (' + RnQUser + ')';
for var Button in Buttons do
ButtonsVar := ButtonsVar + [SymbolToVar(GetEnumName(TypeInfo(TMsgDlgBtn), Ord(Button)))];
if mbOk in Buttons then
DefaultButton := mbOk
else if mbYes in Buttons then
DefaultButton := mbYes
else
DefaultButton := mbRetry;
if mbCancel in Buttons then
CancelButton := mbCancel
else if mbNo in Buttons then
CancelButton := mbNo
else
CancelButton := mbOk;
DefaultButtonVar := SymbolToVar(GetEnumName(TypeInfo(TMsgDlgBtn), Ord(DefaultButton)));
CancelButtonVar := SymbolToVar(GetEnumName(TypeInfo(TMsgDlgBtn), Ord(CancelButton)));
ResultBtn := Call('createDialog', [Icon, Title, Msg, False, ButtonsVar, DefaultButtonVar, CancelButtonVar, Seconds]);
if ResultBtn = 'mbYes' then Result := mrYes
else if ResultBtn = 'mbNo' then Result := mrNo
else if ResultBtn = 'mbOK' then Result := mrOK
else if ResultBtn = 'mbCancel' then Result := mrCancel
else if ResultBtn = 'mbAbort' then Result := mrAbort
else if ResultBtn = 'mbRetry' then Result := mrRetry
else if ResultBtn = 'mbIgnore' then Result := mrIgnore
else if ResultBtn = 'mbAll' then Result := mrAll
else if ResultBtn = 'mbNoToAll' then Result := mrNoToAll
else if ResultBtn = 'mbYesToAll' then Result := mrYesToAll
else if ResultBtn = 'mbHelp' then Result := mrHelp
else if ResultBtn = 'mbClose' then Result := mrClose
else Result := mrOK;
end;
procedure TUI.InitSettings;
var
Settings: TCommonSettings;
begin
Settings.supportAvatars := Account.AccProto.AvatarsSupport;
Settings.avatarShowInHint := AvatarShowInHint;
Settings.avatarUsePalette := AvatarUsePalette10;
Settings.animateWindows := AnimateWindows;
Settings.newSettings := NewSettingsDesign;
Settings.animatedScroll := AnimatedScroll;
Settings.quitConfirmation := QuitConfirmation;
Settings.alertTopMost := AlertTopMost;
Call('initCommonSettings', [RecordToVar(Settings)]);
end;
procedure TUI.LoadData(ASender: TObject; const URL: WideString; ResType: SciterResourceType; RequestId: Pointer; out Discard, Delay, Myself: Boolean);
begin
if (theme.token = 101) and (StartsText('themepic', url) or StartsText('pluginpic:', url) or StartsText('smile:', url)) then
Discard := True // Theme is not loaded yet
else
InitRequest(ASender, URL, ResType, RequestId, Discard, Delay, Myself);
end;
class procedure TCommonMethods.RegisterMethods(var ReturnValue: TSciterValue);
begin
AddMethod('GetWindowCaptionHeight', GetWindowCaptionHeight);
AddMethod('GetTranslation', GetTranslation);
AddMethod('GetTranslations', GetTranslations);
AddMethod('GetSpriteData', GetSpriteData);
AddMethod('GetImageBytes', GetImageBytes);
AddMethod('CheckOnline', CheckOnline);
AddMethod('SetLargeWindowIcon', SetLargeWindowIcon);
AddMethod('GetMaxPasswordLength', GetMaxPasswordLength);
AddMethod('GetPwd', GetPwd);
AddMethod('GetCurrentUserName', GetCurrentUserName);
AddMethod('GetCurrentUserAcc', GetCurrentUserAcc);
AddMethod('GetAccountPassword', GetAccountPassword);
AddMethod('SaveAccountPassword', SaveAccountPassword);
AddMethod('IsAIM', IsAIM);
AddMethod('HTMLDecode', HTMLDecode);
AddMethod('ShowTaskbarButton', ShowTaskbarButton);
AddMethod('HideTaskbarButton', HideTaskbarButton);
AddMethod('HideTaskbarButton2', HideTaskbarButton2);
AddMethod('SavePreviousWindow', SavePreviousWindow);
AddMethod('ClearPreviousWindow', ClearPreviousWindow);
AddMethod('SwitchToPreviousWindow', SwitchToPreviousWindow);
AddMethod('GetContactIdle', GetContactIdle);
AddMethod('GetContactImportant', GetContactImportant);
AddMethod('GetContactIgnored', GetContactIgnored);
AddMethod('GetGroupName', GetGroupName);
AddMethod('GetContactData', GetContactData);
AddMethod('SaveNewAccountPassword', SaveNewAccountPassword);
AddMethod('CheckLockPassword', CheckLockPassword);
AddMethod('OpenLink', OpenLink);
AddMethod('OpenPortal', OpenPortal);
AddMethod('IsOnline', IsOnline);
AddMethod('IsElevated', IsElevated);
AddMethod('IsWindows10', IsWindows10);
AddMethod('IsWindows8', IsWindows8);
AddMethod('ProcessMacro', ProcessMacro);
AddMethod('GetUploadServerName', GetUploadServerName);
AddMethod('GetUpdateInfo', GetUpdateInfo);
AddMethod('GetDoubleClickDelay', GetDoubleClickDelay);
AddMethod('GetWeekDayByNumber', GetWeekDayByNumber);
AddMethod('GetMonthNameByNumber', GetMonthNameByNumber);
AddMethod('PrettyPrint', PrettyPrint);
AddMethod('GetSystemAccentColors', GetSystemAccentColors);
inherited;
end;
procedure TUI.ScriptingCall(ASender: TObject; const Args: TElementOnScriptingCallArgs);
var
CommonNative, MainNative, ChatNative, ViewInfoNative, PrefsNative: TSciterValue;
begin
if not (Args.Method = 'getNativeApis') then
Exit;
TCommonMethods.RegisterMethods(CommonNative);
TTipsMethods.RegisterMethods(CommonNative);
TUsersMethods.RegisterMethods(CommonNative);
TSearchMethods.RegisterMethods(CommonNative);
TOutboxMethods.RegisterMethods(CommonNative);
TDBMethods.RegisterMethods(CommonNative);
TUINListMethods.RegisterMethods(CommonNative);
TMainMethods.RegisterMethods(MainNative);
TCLMethods.RegisterMethods(MainNative);
TStatusMethods.RegisterMethods(MainNative);
TAboutMethods.RegisterMethods(MainNative);
Args.Handled := True;
TChatMethods.RegisterMethods(ChatNative);
TViewInfoMethods.RegisterMethods(ViewInfoNative);
TPrefsMethods.RegisterMethods(PrefsNative);
API.ValueNthElementValueSet(@Args.ReturnSciterValue, 0, @CommonNative);
API.ValueNthElementValueSet(@Args.ReturnSciterValue, 1, @MainNative);
API.ValueNthElementValueSet(@Args.ReturnSciterValue, 2, @ChatNative);
API.ValueNthElementValueSet(@Args.ReturnSciterValue, 3, @ViewInfoNative);
API.ValueNthElementValueSet(@Args.ReturnSciterValue, 4, @PrefsNative);
Args.Handled := True;
end;
end.