unit main; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, ImgList, jalaliLib, HijriLib, Menus, AppEvnts, PrayTimeLib, jpeg, MPlayer, ASGSQLite3, DB, Registry, Math, XMLDoc, xmldom, XMLIntf, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, IdAntiFreezeBase, IdAntiFreeze; type PaintMode = (TilePI, StretchPI, CenterPI); VerInfoTyp = record Ver : string; MajorVer : Word; MinorVer : Word; Release : Word; Build : Word; end; TmainFrm = class(TForm) tryCtrl: TTrayIcon; tryIcon: TImageList; TryPopup: TPopupMenu; Exit1: TMenuItem; N1: TMenuItem; N2: TMenuItem; N3: TMenuItem; N4: TMenuItem; N5: TMenuItem; Hider: TTimer; ApplicationEvents1: TApplicationEvents; N6: TMenuItem; PrayTimeTimer: TTimer; Panel1: TPanel; Label2: TLabel; Label1: TLabel; Image1: TImage; MediaPlayer1: TMediaPlayer; stopAzan: TMenuItem; LiteDB: TASQLite3DB; LiteQuery: TASQLite3Query; MnuPaintOnDesktop: TMenuItem; UpdateTimer: TTimer; IdHTTP1: TIdHTTP; IdAntiFreeze1: TIdAntiFreeze; N7: TMenuItem; verLbl: TLabel; procedure FormCreate(Sender: TObject); procedure N3Click(Sender: TObject); procedure N2Click(Sender: TObject); procedure Exit1Click(Sender: TObject); procedure HiderTimer(Sender: TObject); procedure ApplicationEvents1Deactivate(Sender: TObject); procedure N5Click(Sender: TObject); procedure tryCtrlClick(Sender: TObject); procedure tryCtrlDblClick(Sender: TObject); procedure N6Click(Sender: TObject); procedure PrayTimeTimerTimer(Sender: TObject); procedure stopAzanClick(Sender: TObject); procedure TryPopupPopup(Sender: TObject); function ApplicationEvents1Help(Command: Word; Data: Integer; var CallHelp: Boolean): Boolean; procedure MediaPlayer1Notify(Sender: TObject); procedure FormShow(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure MnuPaintOnDesktopClick(Sender: TObject); procedure UpdateTimerTimer(Sender: TObject); procedure N7Click(Sender: TObject); private showUpdateResult : Boolean; public lat, lng, tZone, sobhAngl, maghribAngl, ishaAngl : Double; calcMtd, asrMtd, nextNotifTime : Word; playAzan : array [0..4] of Boolean; prayerNotify : array [0..4] of Boolean; notificationMsg : string; tryIconDisp : Char; eventsDBs : array of TASQLite3DB; activeEventDBs : WideString; jClickedDate : datePack; DoPaintOnDesktop : Boolean; DskFontSize : Word; DskVertLineSpace : Word; DskHorzLineSpace : Word; DskMargin : Word; monthNameBkColor, monthNameColor, dayNamesColor, daysColor : TColor; procedure createTryIcon(j_d, g_d, h_d : Word); procedure refreshTryIcon(); procedure setDateTryHint(); procedure setAzanTimer(); procedure PaintOnDesktop(); procedure RestoreDesktop(); procedure PaintImg(SrcImg : TGraphic; DesImg : TBitmap; Mode : PaintMode); procedure DrawMonthOnCanvas(Cnv: TBitmap; jDate : datePack); function getDayEvents(j_doy, g_doy, h_doy : datePack) : WideString; function GetVersion: VerInfoTyp; end; var mainFrm: TmainFrm; implementation uses caFace, dateutils, Options, about, dateDetails, messageBox; {$R *.dfm} var timeName : array [0..4] of string = ( 'صبح', 'ظهر', 'عصر', 'مغرب', 'عشا' ); DaysNames : array [1..7] of WideString = ('ش','ی','د','س','چ','پ','ج'); procedure TmainFrm.ApplicationEvents1Deactivate(Sender: TObject); begin if caFaceFrm.showing then caFaceFrm.CaFadeOut(); end; function TmainFrm.ApplicationEvents1Help(Command: Word; Data: Integer; var CallHelp: Boolean): Boolean; begin CallHelp := False; ShowMessage('برای دریافت اطلاعات بیشتر و راهنمایی به آدرس زیر مراجعه نمایید'+#13 +'http://sourceforge.net/projects/permulcalendar'); Result := True; end; procedure TmainFrm.createTryIcon(j_d, g_d, h_d : Word); var tmpBmp : TBitmap; iconRect : TRect; begin iconRect := rect(0,0,16,16); tryCtrl.Icons := nil; tryIcon.Clear; tmpBmp := TBitmap.Create; tmpBmp.Width := 16; tmpBmp.Height := 16; tmpBmp.Canvas.Brush.Color := clBtnFace; tmpBmp.Canvas.FillRect(iconRect); tmpBmp.Canvas.Font.Size := 9; tmpBmp.Canvas.Font.Style := [fsBold]; tmpBmp.Canvas.Font.Color := clBtnText; if tryIconDisp = 'J' then DrawTextW(tmpBmp.Canvas.Handle, pwidechar(ConvToFarDigit(IntToStr(j_d))), Length(IntToStr(j_d)), iconRect, DT_CENTER) else if tryIconDisp = 'G' then DrawText(tmpBmp.Canvas.Handle, pchar(IntToStr(g_d)), Length(IntToStr(g_d)), iconRect, DT_CENTER) else DrawTextW(tmpBmp.Canvas.Handle, pwidechar(ConvToFarDigit(IntToStr(h_d))), Length(IntToStr(h_d)), iconRect, DT_CENTER); tryIcon.AddMasked(tmpBmp, clWhite); tryCtrl.Icons := tryIcon; tryCtrl.IconIndex := tryIcon.Count-1; end; procedure TmainFrm.DrawMonthOnCanvas(Cnv: TBitmap; jDate: datePack); var OffsetX, OffsetY, DskWidth, DskHeight, monOffset, CurDay, monCount, markNow : Word; tmpRect : TRect; begin // DskWidth := (7 * DskFontSize + 6 * DskHorzLineSpace ); DskHeight := (9 * DskFontSize + 6 * DskVertLineSpace ); OffsetX := Cnv.Width - DskWidth - DskMargin; OffsetY := Cnv.Height - DskHeight - DskMargin; Cnv.Canvas.Font.Size := DskFontSize; //draw the name of month tmpRect := rect(OffsetX, OffsetY, OffsetX + DskWidth, OffsetY + 2*DskFontSize); Cnv.Canvas.Pen.Color := monthNameBkColor; Cnv.Canvas.Brush.Color := monthNameBkColor; Cnv.Canvas.RoundRect(tmpRect.Left, tmpRect.Top, tmpRect.Right, tmpRect.Bottom, 8,8); Cnv.Canvas.Font.Color := monthNameColor; SetBkMode(Cnv.Canvas.Handle, TRANSPARENT); DrawTextW(Cnv.Canvas.Handle, pwidechar(get_jmonth_name(jDate.Month)), length(get_jmonth_name(jDate.Month)), tmpRect, DT_CENTER or DT_SINGLELINE or DT_VCENTER); //draw days monOffset := month_first_day_of_week(jDate.Year, jDate.Month); monCount := month_day_count(jDate.Year, jDate.Month); Inc(OffsetY, 2*DskFontSize); //draw day's names Cnv.Canvas.Font.Color := dayNamesColor; for CurDay := 1 to 7 do begin OffsetX := Cnv.Width - DskMargin - ( (((CurDay -1) mod 7) * DskFontSize) + (((CurDay -1) mod 7) + 1) * DskHorzLineSpace ); tmpRect := Rect(OffsetX, OffsetY, OffsetX + 2*DskFontSize, OffsetY + 2*DskFontSize); DrawTextW(Cnv.Canvas.Handle, pwidechar(DaysNames[CurDay]), Length(DaysNames[CurDay]), tmpRect, DT_CENTER or DT_SINGLELINE or DT_VCENTER); end; Cnv.Canvas.Font.Color := daysColor; if (jNow.Year = jDate.Year) and (jNow.Month = jDate.Month) then markNow := jNow.Day else markNow := 0; for CurDay := 1 to monCount do begin if (((monOffset + CurDay - 1) mod 7) = 1) or (CurDay = 1) then begin Inc(OffsetY, DskFontSize + DskVertLineSpace); end; OffsetX := Cnv.Width - DskMargin - ( (((CurDay + monOffset -2) mod 7) * DskFontSize) + (((CurDay + monOffset -2) mod 7) + 1) * DskHorzLineSpace ); // Dec(OffsetX, DskFontSize + DskHorzLineSpace); tmpRect := Rect(OffsetX, OffsetY, OffsetX + 2*DskFontSize, OffsetY + 2*DskFontSize); if markNow = CurDay then begin Cnv.Canvas.Brush.Color := clNone; Cnv.Canvas.Pen.Color := clRed; SetBkMode(Cnv.Canvas.Handle, TRANSPARENT); Cnv.Canvas.RoundRect(tmpRect.Left, tmpRect.Top, tmpRect.Right, tmpRect.Bottom, 8,8); end; DrawTextW(Cnv.Canvas.Handle, pwidechar(ConvToFarDigit(CurDay)), Length(ConvToFarDigit(CurDay)), tmpRect, DT_CENTER or DT_SINGLELINE or DT_VCENTER); end; end; procedure TmainFrm.Exit1Click(Sender: TObject); begin Application.Terminate; end; procedure TmainFrm.FormCreate(Sender: TObject); begin showUpdateResult := False; AddFontResource(pchar(extractfiledir(ParamStr(0)) + '\IranNastaliq.ttf')); SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0) ; end; procedure TmainFrm.FormDestroy(Sender: TObject); begin RestoreDesktop; end; procedure TmainFrm.FormShow(Sender: TObject); begin verLbl.Caption := GetVersion.Ver; Hider.Enabled := True; mainFrm.BringToFront; optionsFrm.loadSettings; setDateTryHint; end; function TmainFrm.getDayEvents(j_doy, g_doy, h_doy: datePack): WideString; var FindResult: integer; SearchRec : TSearchRec; Path, tmpStr : string; ResultXML : TXMLDocument; CurNode : IXMLNode; holiday : Boolean; begin //We need to export an XML to be parsed outside if activeEventDBs = '' then Exit; ResultXML := TXMLDocument.Create(Self); ResultXML.DOMVendor := DOMVendors.Find('OXMLDOM'); ResultXML.Active := True; ResultXML.AddChild('Events'); ResultXML.DocumentElement.AddChild('HIJ'); ResultXML.DocumentElement.AddChild('JAL'); ResultXML.DocumentElement.AddChild('GRE'); Path := ExtractFileDir(Application.ExeName) + '\DB\events\'; holiday := False; Result := ''; FindResult := FindFirst(Path + '*.s3db', faAnyFile - faDirectory, SearchRec); while FindResult = 0 do begin if pos(SearchRec.Name, activeEventDBs) > 0 then begin LiteDB.Database := Path + SearchRec.Name; try LiteQuery.SQL.Text := 'SELECT `value` FROM db_definition WHERE `name`="CALENDAR"'; LiteQuery.Open; tmpStr := LiteQuery.FieldByName('value').AsString; if LowerCase(tmpStr) = 'hij' then begin LiteQuery.SQL.Text := 'SELECT `name`,`description`,`holiday`'+ ' FROM events WHERE `month`="'+IntToStr(h_doy.Month)+ '" AND `day`="'+IntToStr(h_doy.Day)+'"'; end else if LowerCase(tmpStr) = 'jal' then begin LiteQuery.SQL.Text := 'SELECT `name`,`description`,`holiday`'+ ' FROM events WHERE `month`="'+IntToStr(j_doy.Month)+ '" AND `day`="'+IntToStr(j_doy.Day)+'"'; end else if LowerCase(tmpStr) = 'gre' then begin LiteQuery.SQL.Text := 'SELECT `name`,`description`,`holiday`'+ ' FROM events WHERE `month`='+IntToStr(g_doy.Month)+ ' AND `day`='+IntToStr(g_doy.Day); end; LiteQuery.Open; if not LiteQuery.IsEmpty then begin while not LiteQuery.Eof do begin holiday := (LowerCase(LiteQuery.FieldByName('holiday').AsString) = 'y'); CurNode := ResultXML.DocumentElement.ChildNodes.FindNode(UpperCase(tmpStr)); CurNode.AddChild('event'); CurNode.ChildNodes.Last.Attributes['holiday'] := holiday; CurNode.ChildNodes.Last.Text := LiteQuery.FieldByName('description').AsString; CurNode.ChildNodes.Last.Attributes['name'] := LiteQuery.FieldByName('name').AsString; LiteQuery.Next; end; end; finally LiteDB.Close; end; end; FindResult := FindNext(SearchRec); end; FindClose(SearchRec); Result := ResultXML.XML.Text; ResultXML.Free; end; procedure TmainFrm.HiderTimer(Sender: TObject); begin mainFrm.Hide; end; procedure TmainFrm.MediaPlayer1Notify(Sender: TObject); begin if MediaPlayer1.Mode = mpPlaying then MediaPlayer1.Close; end; procedure TmainFrm.N2Click(Sender: TObject); begin caFaceFrm.jCurrDate := jNow; caFaceFrm.Show; end; procedure TmainFrm.N3Click(Sender: TObject); begin with ToptionsFrm.Create(nil) do try ShowModal; finally Free; end; end; procedure TmainFrm.N5Click(Sender: TObject); begin with TaboutFrm.Create(nil) do try ShowModal; finally Free; end; end; procedure TmainFrm.N6Click(Sender: TObject); begin { if dateDetailsFrm.Showing then begin ShowMessage('شما در حال مشاهده جزئیات تاریخ دیگری هستید.'+ #13 + 'لطفا ابتدا آن پنجره را ببندید.'); Exit; end;} jClickedDate := gregorian_to_jalali(YearOf(Now), MonthOf(Now), DayOf(Now)); with TdateDetailsFrm.Create(nil) do try ShowModal; finally Free; end; end; procedure TmainFrm.N7Click(Sender: TObject); begin showUpdateResult := True; UpdateTimer.OnTimer(Self); showUpdateResult := false; end; procedure TmainFrm.MnuPaintOnDesktopClick(Sender: TObject); begin PaintOnDesktop; end; procedure TmainFrm.stopAzanClick(Sender: TObject); begin MediaPlayer1.Stop; MediaPlayer1.Close; end; procedure TmainFrm.PaintImg(SrcImg: TGraphic; DesImg: TBitmap; Mode: PaintMode); var x,y : Word; MyReg : TRegistry; BgCR, BgCG, BgCB : Byte; tmpstr : string; begin if (SrcImg.Width = 0) or (SrcImg.Height = 0) then exit; try MyReg := TRegistry.Create; MyReg.RootKey := HKEY_CURRENT_USER; if MyReg.OpenKey('Control Panel\Colors', false) then begin tmpstr := MyReg.ReadString('Background'); BgCR := StrToInt(Copy(tmpstr, 1, Pos(' ', tmpstr)-1)); Delete(tmpstr, 1, pos(' ', tmpstr)); BgCG := StrToInt(Copy(tmpstr, 1, Pos(' ', tmpstr)-1)); Delete(tmpstr, 1, pos(' ', tmpstr)); BgCB := StrToInt(Copy(tmpstr, 1, length(tmpstr))); end; DesImg.Canvas.Brush.Color := RGB(BgCR, BgCG, BgCB); DesImg.Canvas.FillRect(Rect(0, 0, DesImg.Width, DesImg.Height)); except exit; end; case Mode of TilePI: begin y := 0; while y <= DesImg.Height do begin x := 0; while x <= DesImg.Width do begin DesImg.Canvas.Draw(x, y, SrcImg); inc(x, SrcImg.Width); end; inc(y, SrcImg.Height) end; end; StretchPI: begin DesImg.Canvas.StretchDraw(Rect(0, 0, DesImg.Width, DesImg.Height ), SrcImg); end; CenterPI: begin DesImg.Canvas.Draw( (DesImg.Width - SrcImg.Width) div 2, (DesImg.Height - SrcImg.Height) div 2, SrcImg ); //draw centered end; end; end; procedure TmainFrm.PaintOnDesktop; var Img, OrgImg : TBitmap; WPAddr, WPStyle, WPTile : string; MyReg : TRegistry; begin //Here we draw on desktop if allowed if not DoPaintOnDesktop then Exit; //first get the Wallpaper: try MyReg := TRegistry.Create; MyReg.RootKey := HKEY_CURRENT_USER; try if MyReg.OpenKey('Control Panel\Desktop', False) then begin WPAddr := MyReg.ReadString('Wallpaper'); if (WPAddr = ExtractFilePath(ParamStr(0))+'back.bmp') and (MyReg.ValueExists('PMCWallpaper')) then WPAddr := MyReg.ReadString('PMCWallpaper'); if not FileExists(WPAddr) then begin ShowMessage('خطا: فایل تصویر پس زمینه وجود ندارد'); Exit; end; WPStyle := MyReg.ReadString('WallpaperStyle'); WPTile := MyReg.ReadString('TileWallpaper'); Img := TBitmap.Create; OrgImg := TBitmap.Create; OrgImg.LoadFromFile(WPAddr); Img.Height := Screen.Height; Img.Width := Screen.Width; //Centered if (WPStyle = '0') and (WPTile = '0') then PaintImg(OrgImg, Img, CenterPI) //Tiled else if (WPStyle = '0') and (WPTile = '1') then PaintImg(OrgImg, Img, TilePI) //Stretched else if WPStyle = '2' then PaintImg(OrgImg, Img, StretchPI); //Write realy into desktop DrawMonthOnCanvas(Img, jNow); Img.SaveToFile(ExtractFilePath(ParamStr(0))+'back.bmp'); MyReg.WriteString('PMCWallpaper', WPAddr); SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, Pchar(ExtractFilePath(ParamStr(0))+'back.bmp'), SPIF_UPDATEINIFILE); end; except ShowMessage('در نمایش روی دسکتاپ مشکلی پیش آمد.'); end; finally MyReg.Free; end; end; procedure TmainFrm.PrayTimeTimerTimer(Sender: TObject); var msg : string; begin if prayerNotify[nextNotifTime] then begin if pos('