1{%MainUnit fpguiint.pp} 2{ 3 ***************************************************************************** 4 This file is part of the Lazarus Component Library (LCL) 5 6 See the file COPYING.modifiedLGPL.txt, included in this distribution, 7 for details about the license. 8 ***************************************************************************** 9} 10//--------------------------------------------------------------- 11 12type 13 14 { TFPGUITimer } 15 16 TFPGUITimer = class 17 private 18 //FLCLTimer: TTimer; 19 FTimer: TfpgTimer; 20 FCallback: TWSTimerProc; 21 protected 22 procedure FPGTimer(Sender: TObject); 23 public 24 constructor Create(AInterval: Integer; ACallbackFunc: TWSTimerProc); 25 destructor Destroy; override; 26 27 property Timer : TfpgTimer read FTimer; 28 end; 29 30{ TFPGUITimer } 31 32procedure TFPGUITimer.FPGTimer(Sender: TObject); 33begin 34 if Assigned(FCallback) then 35 FCallback; 36end; 37 38constructor TFPGUITimer.Create(AInterval: Integer; ACallbackFunc: TWSTimerProc); 39begin 40 FTimer := TfpgTimer.Create(AInterval); 41 FTimer.OnTimer:=@FPGTimer; 42 FCallback := ACallbackFunc; 43 FTimer.Enabled:= True; 44end; 45 46destructor TFPGUITimer.Destroy; 47begin 48 FTimer.Free; 49 inherited Destroy; 50end; 51 52 53{------------------------------------------------------------------------------ 54 Method: TFpGuiWidgetSet.Create 55 Params: None 56 Returns: Nothing 57 58 Constructor for the class. 59 ------------------------------------------------------------------------------} 60constructor TFpGuiWidgetSet.Create; 61begin 62 inherited Create; 63 64 FpGuiWidgetSet := Self; 65end; 66 67{------------------------------------------------------------------------------ 68 Method: TFpGuiWidgetSet.Destroy 69 Params: None 70 Returns: Nothing 71 72 Destructor for the class. 73 ------------------------------------------------------------------------------} 74destructor TFpGuiWidgetSet.Destroy; 75begin 76 FpGuiWidgetSet := nil; 77 78 inherited Destroy; 79end; 80 81function TFpGuiWidgetSet.DrawFrameControl(DC: HDC; const Rect: TRect; uType, 82 uState: Cardinal): Boolean; 83var 84 ADC: TFPGUIDeviceContext; 85 ControlType: Cardinal; 86 ControlStyle: Cardinal; 87 fpgRect: TfpgRect; 88 Style: TfpgButtonFlags; 89 (* 90 DFC_CAPTION = $01; 91 DFC_MENU = $02; 92 DFC_SCROLL = $03; 93 DFC_BUTTON = $04; 94 DFCS_BUTTONCHECK = 0; 95 DFCS_BUTTONRADIOIMAGE = 1; 96 DFCS_BUTTONRADIOMASK = 2; 97 DFCS_BUTTONRADIO = 4; 98 DFCS_BUTTON3STATE = 8; 99 DFCS_BUTTONPUSH = 16; 100 *) 101const 102 DFCS_ALLSTATES=DFCS_BUTTONCHECK or DFCS_BUTTONRADIOIMAGE or DFCS_BUTTONRADIOMASK 103 or DFCS_BUTTONRADIO or DFCS_BUTTON3STATE or DFCS_BUTTONPUSH; 104begin 105 Result:=false; 106 ADC:=TFPGUIDeviceContext(DC); 107 if Assigned(ADC.fpgCanvas) then begin 108 ControlType:=uType; 109 ControlStyle:=uState and DFCS_ALLSTATES; 110 fpgRect:=ADC.PrepareRectOffsets(Rect); 111 Case ControlType of 112 DFC_BUTTON: 113 begin 114 if (ControlStyle and DFCS_BUTTONPUSH)=DFCS_BUTTONPUSH then begin 115 Style:=[]; 116 if (uState and DFCS_INACTIVE) <> 0 then 117 Style:=Style+[btfIsEmbedded] //Disabled ? 118 else 119 if (uState and DFCS_PUSHED) <> 0 then 120 Style:=Style+[btfIsPressed] 121 else 122 if (uState and DFCS_HOT) <> 0 then 123 Style:=Style+[btfHover]; 124 ADC.fpgCanvas.DrawButtonFace(fpgRect,Style); 125 Result:=true; 126 end; 127 end; 128 else 129 Result:=false; 130 end; 131 end; 132end; 133 134{------------------------------------------------------------------------------ 135 Method: TFpGuiWidgetSet.CreateTimer 136 Params: None 137 Returns: Nothing 138 139 Creates a new timer and sets the callback event. 140 ------------------------------------------------------------------------------} 141function TFpGuiWidgetSet.CreateTimer(Interval: integer; TimerFunc: TWSTimerProc): THandle; 142var 143 Timer: TFPGUITimer; 144begin 145 Timer := TFPGUITimer.Create(Interval, TimerFunc); 146 147 Result := PtrInt(Timer); 148end; 149 150{------------------------------------------------------------------------------ 151 Method: TFpGuiWidgetSet.DestroyTimer 152 Params: None 153 Returns: Nothing 154 155 Destroys a timer. 156 ------------------------------------------------------------------------------} 157function TFpGuiWidgetSet.DestroyTimer(TimerHandle: THandle): boolean; 158var 159 Timer: TFPGUITimer absolute TimerHandle; 160begin 161 if Timer <> nil then 162 Timer.Free; 163 164 Result := True; 165end; 166 167function TFpGuiWidgetSet.CreateThemeServices: TThemeServices; 168begin 169 Result:=TFPGUIThemeServices.Create; 170end; 171 172{------------------------------------------------------------------------------ 173 Method: TFpGuiWidgetSet.AppInit 174 Params: None 175 Returns: Nothing 176 177 Initializes the application 178 ------------------------------------------------------------------------------} 179procedure TFpGuiWidgetSet.AppInit(var ScreenInfo: TScreenInfo); 180//var 181// Display: String; 182begin 183 // This doesn't hurt. on other playforms than X it just will do nothing 184// Display := GetEnvironmentVariableUTF8('DISPLAY'); 185 fpgApplication.Initialize; 186 //GFApplication.QuitWhenLastWindowCloses := False; 187 188 //if fpgStyleManager.SetStyle('win8') then begin 189 // fpgStyle:=fpgStyleManager.Style; 190 //end; 191 192end; 193 194{------------------------------------------------------------------------------ 195 Method: TFpGuiWidgetSet.AppRun 196 Params: None 197 Returns: Nothing 198 199 Enter the main message loop 200 ------------------------------------------------------------------------------} 201procedure TFpGuiWidgetSet.AppRun(const ALoop: TApplicationMainLoop); 202var 203 vMainForm: TfpgForm; 204begin 205 { Shows the main form } 206 if Assigned(Application.MainForm) then 207 begin 208 vMainForm := TFPGUIPrivateWindow(Application.MainForm.Handle).Form; 209 if Application.MainForm.Visible then 210 vMainForm.Show; 211 end; 212 // GFApplication.EventFilter can maybe be used on X11 for aloop but it is X only 213// fpgApplication.Run; 214 if Assigned(ALoop) then begin 215 ALoop 216 end else begin 217 repeat 218 try 219 fpgApplication.ProcessMessages; 220 if not fpgApplication.Terminated then Application.Idle(true); 221 except 222 Application.HandleException(Self); 223 end; 224 until fpgApplication.Terminated; 225 end; 226 227end; 228 229{------------------------------------------------------------------------------ 230 Method: TFpGuiWidgetSet.AppWaitMessage 231 Params: None 232 Returns: Nothing 233 234 Wait till an OS application message is received 235 ------------------------------------------------------------------------------} 236procedure TFpGuiWidgetSet.AppWaitMessage; 237begin 238 fpgWaitWindowMessage; 239end; 240 241{------------------------------------------------------------------------------ 242 Method: TFpGuiWidgetSet.AppProcessMessage 243 Params: None 244 Returns: Nothing 245 246 Handle the messages in the queue 247 ------------------------------------------------------------------------------} 248procedure TFpGuiWidgetSet.AppProcessMessages; 249begin 250 fpgApplication.ProcessMessages; 251end; 252 253{------------------------------------------------------------------------------ 254 Method: TFpGuiWidgetSet.AppTerminate 255 Params: None 256 Returns: Nothing 257 258 Implements Application.Terminate and MainForm.Close. 259 ------------------------------------------------------------------------------} 260procedure TFpGuiWidgetSet.AppTerminate; 261begin 262 fpgApplication.Terminated := True; 263end; 264 265{------------------------------------------------------------------------------ 266 Method: TFpGuiWidgetSet.AppMinimize 267 Params: None 268 Returns: Nothing 269 270 Minimizes the application window. 271 ------------------------------------------------------------------------------} 272procedure TFpGuiWidgetSet.AppMinimize; 273begin 274end; 275 276procedure TFpGuiWidgetSet.AppRestore; 277begin 278 279end; 280 281{------------------------------------------------------------------------------ 282 Method: TFpGuiWidgetSet.AppBringToFront 283 Params: None 284 Returns: Nothing 285 286 Brings the application window to the front 287 ------------------------------------------------------------------------------} 288procedure TFpGuiWidgetSet.AppBringToFront; 289begin 290 291end; 292 293function TFpGuiWidgetSet.LCLPlatform: TLCLPlatform; 294begin 295 Result:= lpfpGUI; 296end; 297 298function TFpGuiWidgetSet.DCGetPixel(CanvasHandle: HDC; X, Y: integer): TGraphicsColor; 299begin 300 Result:=clNone; 301end; 302 303procedure TFpGuiWidgetSet.DCSetPixel(CanvasHandle: HDC; X, Y: integer; AColor: TGraphicsColor); 304var 305 DC: TFPGUIDeviceContext; 306 p: TPoint; 307begin 308 DC:=TFPGUIDeviceContext(CanvasHandle); 309 p:=Point(X,Y); 310 p:=DC.PreparePointOffsets(p); 311 DC.FPrivateWidget.Widget.Canvas.Pixels[p.x,p.y]:=TColorToTfpgColor(AColor); 312end; 313 314procedure TFpGuiWidgetSet.DCRedraw(CanvasHandle: HDC); 315begin 316 317end; 318 319procedure TFpGuiWidgetSet.SetDesigning(AComponent: TComponent); 320begin 321// Include(AComponent.ComponentState, csDesigning); 322end; 323 324function TFpGuiWidgetSet.RawImage_CreateBitmaps(const ARawImage: TRawImage; out 325 ABitmap, AMask: HBitmap; ASkipMask: Boolean): Boolean; 326var 327 OutBitmap: TFPGUIWinAPIBitmap; 328 fpgBitmap: TfpgImage; 329 ImgData: Pointer absolute ARawImage.Data; 330 ImgMask: Pointer absolute ARawImage.Mask; 331 ImgWidth: Cardinal absolute ARawImage.Description.Width; 332 ImgHeight: Cardinal absolute ARawImage.Description.Height; 333 ImgDepth: Byte absolute ARawImage.Description.Depth; 334 ImgDataSize: PtrUInt absolute ARawImage.DataSize; 335 function min(const a,b: SizeInt): SizeInt; 336 begin 337 if a>b then Result:=b else Result:=a; 338 end; 339begin 340 ABitmap:=0; 341 AMask:=0; 342 Result:=false; 343 OutBitmap:=TFPGUIWinAPIBitmap.Create(ARawImage.Description.BitsPerPixel,ARawImage.Description.Width,ARawImage.Description.Height); 344 fpgBitmap:=OutBitmap.Image; 345 ABitmap:=HBITMAP(OutBitmap); 346 move(ARawImage.Data^,pbyte(fpgBitmap.ImageData)^,min(ARawImage.DataSize,fpgBitmap.ImageDataSize)); 347 fpgBitmap.UpdateImage; 348 Result:=true; 349end; 350 351procedure FillRawImageDescriptionColors(var ADesc: TRawImageDescription); 352begin 353 case ADesc.BitsPerPixel of 354 1,4,8: 355 begin 356 // palette mode, no offsets 357 ADesc.Format := ricfGray; 358 ADesc.RedPrec := ADesc.BitsPerPixel; 359 ADesc.GreenPrec := 0; 360 ADesc.BluePrec := 0; 361 ADesc.RedShift := 0; 362 ADesc.GreenShift := 0; 363 ADesc.BlueShift := 0; 364 end; 365 16: 366 begin 367 // 5-5-5 mode 368 ADesc.RedPrec := 5; 369 ADesc.GreenPrec := 5; 370 ADesc.BluePrec := 5; 371 ADesc.RedShift := 10; 372 ADesc.GreenShift := 5; 373 ADesc.BlueShift := 0; 374 ADesc.Depth := 15; 375 end; 376 24: 377 begin 378 // 8-8-8 mode 379 ADesc.RedPrec := 8; 380 ADesc.GreenPrec := 8; 381 ADesc.BluePrec := 8; 382 ADesc.RedShift := 16; 383 ADesc.GreenShift := 8; 384 ADesc.BlueShift := 0; 385 end; 386 else // 32: 387 // 8-8-8-8 mode, high byte can be native alpha or custom 1bit maskalpha 388 ADesc.AlphaPrec := 8; 389 ADesc.RedPrec := 8; 390 ADesc.GreenPrec := 8; 391 ADesc.BluePrec := 8; 392 ADesc.AlphaShift := 24; 393 ADesc.RedShift := 16; 394 ADesc.GreenShift := 8; 395 ADesc.BlueShift := 0; 396 ADesc.Depth := 32; 397 end; 398end; 399 400procedure FillRawImageDescription(const ABitmapInfo: TfpgImage; out ADesc: TRawImageDescription); 401begin 402 ADesc.Init; 403 ADesc.Format := ricfRGBA; 404 ADesc.Depth := 32; // used bits per pixel 405 ADesc.Width := ABitmapInfo.Width; 406 ADesc.Height := ABitmapInfo.Height; 407 ADesc.BitOrder := riboReversedBits; 408 ADesc.ByteOrder := riboLSBFirst; 409 ADesc.LineOrder := riloTopToBottom; 410 ADesc.BitsPerPixel := 32; // bits per pixel. can be greater than Depth. 411 ADesc.LineEnd := rileDWordBoundary; 412 413 if ADesc.BitsPerPixel <= 8 414 then begin 415 // each pixel is an index in the palette 416 // TODO, ColorCount 417 ADesc.PaletteColorCount := 0; 418 end 419 else ADesc.PaletteColorCount := 0; 420 421 FillRawImageDescriptionColors(ADesc); 422 423 ADesc.MaskBitsPerPixel := 8; 424 ADesc.MaskShift := 0; 425 ADesc.MaskLineEnd := rileWordBoundary; // CreateBitmap requires word boundary 426 ADesc.MaskBitOrder := riboReversedBits; 427end; 428 429function TFpGuiWidgetSet.RawImage_DescriptionFromBitmap(ABitmap: HBITMAP; out ADesc: TRawImageDescription): Boolean; 430var 431 o: TFPGUIWinAPIBitmap; 432begin 433 o:=TFPGUIWinAPIBitmap(ABitmap); 434 FillRawImageDescription(o.Image,ADesc); 435 Result:=true; 436end; 437 438function TFpGuiWidgetSet.RawImage_DescriptionFromDevice(ADC: HDC; out ADesc: TRawImageDescription): Boolean; 439var 440 DC: TFPGUIDeviceContext; 441 r: TfpgRect; 442begin 443 DC:=TFPGUIDeviceContext(ADC); 444 ADesc.Init; 445 with ADesc do begin 446 Format:= ricfRGBA; 447 if Assigned(DC) and Assigned(DC.fpgCanvas) then begin 448 dc.fpgCanvas.GetWinRect(r); 449 Width:= r.Width; 450 Height:= r.Height; 451 end else begin 452 Width:= 0; 453 Height:= 0; 454 end; 455 Depth:= 32; // used bits per pixel 456 BitOrder:= riboBitsInOrder; 457 ByteOrder:= riboMSBFirst; 458 LineOrder:= riloTopToBottom; 459 LineEnd:= rileByteBoundary; 460 BitsPerPixel:=32; // bits per pixel. can be greater than Depth. 461 RedPrec:= 8; // red or gray precision. bits for red 462 RedShift:= 8; // bitshift. Direction: from least to most significant 463 GreenPrec:= 8; 464 GreenShift:= 16; 465 BluePrec:= 8; 466 BlueShift:= 24; 467 AlphaPrec:= 8; 468 AlphaShift:= 0; 469 // Test 470 471 // The next values are only valid, if there is a mask (MaskBitsPerPixel > 0) 472 // Masks are always separate with a depth of 1 bpp. One pixel can occupy 473 // one byte at most 474 // a value of 1 means that pixel is masked 475 // a value of 0 means the pixel value is shown 476 MaskBitsPerPixel:= 8; 477 MaskShift:= 0; 478 MaskLineEnd:= rileWordBoundary; 479 MaskBitOrder:= riboReversedBits; 480 end; 481 Result:=true; 482end; 483 484procedure TFpGuiWidgetSet.InitializeCriticalSection( 485 var CritSection: TCriticalSection); 486var 487 ACritSec: System.PRTLCriticalSection; 488begin 489 New(ACritSec); 490 System.InitCriticalSection(ACritSec^); 491 CritSection:=TCriticalSection(ACritSec); 492end; 493 494procedure TFpGuiWidgetSet.DeleteCriticalSection( 495 var CritSection: TCriticalSection); 496var 497 ACritSec: System.PRTLCriticalSection; 498begin 499 ACritSec:=System.PRTLCriticalSection(CritSection); 500 System.DoneCriticalsection(ACritSec^); 501 Dispose(ACritSec); 502 CritSection:=0; 503end; 504 505procedure TFpGuiWidgetSet.EnterCriticalSection(var CritSection: TCriticalSection); 506var 507 ACritSec: System.PRTLCriticalSection; 508begin 509 ACritSec:=System.PRTLCriticalSection(CritSection); 510 System.EnterCriticalsection(ACritSec^); 511end; 512 513procedure TFpGuiWidgetSet.LeaveCriticalSection(var CritSection: TCriticalSection); 514var 515 ACritSec: System.PRTLCriticalSection; 516begin 517 ACritSec:=System.PRTLCriticalSection(CritSection); 518 System.LeaveCriticalsection(ACritSec^); 519end; 520 521{------------------------------------------------------------------------------ 522 Function: TFpGuiWidgetSet.IsValidDC 523 Params: DC - handle to a device context (TFpGuiDeviceContext) 524 Returns: True - if the DC is valid 525 ------------------------------------------------------------------------------} 526function TFpGuiWidgetSet.IsValidDC(const DC: HDC): Boolean; 527begin 528 Result := (DC <> 0); 529end; 530 531{------------------------------------------------------------------------------ 532 Function: TFpGuiWidgetSet.IsValidGDIObject 533 Params: GDIObject - handle to a GDI Object (TFpGuiFont, TFpGuiBrush, etc) 534 Returns: True - if the DC is valid 535 536 Remark: All handles for GDI objects must be pascal objects so we can 537 distinguish between them 538 ------------------------------------------------------------------------------} 539function TFpGuiWidgetSet.IsValidGDIObject(const GDIObject: HGDIOBJ): Boolean; 540var 541 aObject: TObject; 542begin 543 Result := False; 544 545 if GDIObject = 0 then Exit; 546 547 aObject := TObject(GDIObject); 548 549 try 550 if aObject is TObject then 551 begin 552 Result:= (aObject is TFPGUIWinAPIObject); 553 end; 554 except 555 //Eat exceptions. If Exception happends it is not a TObject after all and 556 //of course it is not a fpgui GDI object. 557 end; 558end; 559 560{ Unable to make it work properly 561function TFpGuiWidgetSet.CreateRubberBand(const ARect: TRect; 562 const ABrush: HBrush): HWND; 563var 564 FakeParams: TCreateParams; 565 fpgForm: TfpgForm; 566begin 567 FillByte(FakeParams,sizeof(FakeParams),0); 568 FakeParams.Style:=FakeParams.Style or WS_VISIBLE; 569 FakeParams.X:=ARect.Left; 570 FakeParams.Y:=ARect.Top; 571 FakeParams.Width:=aRect.Width; 572 FakeParams.Height:=aRect.Height; 573 Result:=HWND(TFPGUIPrivateWindow.Create(nil,FakeParams)); 574 fpgForm:=TFPGUIPrivateWindow(Result).Form; 575 TFPGUIPrivateWindow(Result).SetFormBorderStyle(TFormBorderStyle.bsNone); 576 fpgForm.Show; 577end; 578 579procedure TFpGuiWidgetSet.DestroyRubberBand(ARubberBand: HWND); 580begin 581 TFPGUIPrivateWindow(ARubberBand).Free; 582end; 583} 584 585function TFpGuiWidgetSet.RawImage_FromBitmap(out ARawImage: TRawImage; ABitmap, 586 AMask: HBITMAP; ARect: PRect): Boolean; 587var 588 img: TFPGUIWinAPIBitmap; 589begin 590 ARawImage.Init; 591 img:=TFPGUIWinAPIBitmap(ABitmap); 592 FillRawImageDescription(img.Image, ARawImage.Description); 593 ARawImage.DataSize:=ARawImage.Description.Width*ARawImage.Description.Height*4; 594 ARawImage.Data:=GetMem(ARawImage.DataSize); 595 move(img.Image.ImageData^,ARawImage.Data^,img.Image.ImageDataSize); 596end; 597 598//------------------------------------------------------------------------ 599