SDL2 drag and drop image [SOLVED] lazarus / 39-Graphics ---------------------------------------------------------------------- Pe3s · 2024-11-20 22:32 Hello, I'm writing a program that wants to create drag and drop functionality. When compiling there is an error unit1.pas(124,45) Error: Syntax error, "identifier" expected but "FILE" found. Could I ask for help in solving the problem? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ComCtrls, ExtCtrls,  StdCtrls, SDL2, SDL2_image, Math; type   { TForm1 }   TForm1 = class(TForm)    Button1: TButton;    OpenDialog1: TOpenDialog;    Panel1: TPanel;    Panel2: TPanel;    StatusBar1: TStatusBar;    procedure Button1Click(Sender: TObject);    procedure FormDestroy(Sender: TObject);    procedure FormResize(Sender: TObject);    procedure FormShow(Sender: TObject);    procedure Panel1Paint(Sender: TObject);  private      SDLWindow: PSDL_Window;      SDLRenderer: PSDL_Renderer;      CurrentTexture: PSDL_Texture;      procedure InitializeSDL;      procedure ShutdownSDL;      procedure LoadAndDisplayImage(const FileName: string);      procedure RenderImage;      procedure HandleDropEvent(const FileName: string);      procedure HandleSDLEvents;   public   end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.InitializeSDL;begin  if SDL_Init(SDL_INIT_VIDEO) < 0 then    raise Exception.Create('Nie udało się zainicjować SDL: ' + SDL_GetError);   SDLWindow := SDL_CreateWindowFrom(Pointer(Panel1.Handle));  if SDLWindow = nil then    raise Exception.Create('Nie udało się utworzyć okna SDL: ' + SDL_GetError);   SDLRenderer := SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED or SDL_RENDERER_PRESENTVSYNC);;  if SDLRenderer = nil then    raise Exception.Create('Nie można utworzyć renderowania SDL: ' + SDL_GetError);      // Enable the drag-and-drop feature  SDL_SetWindowGrab(SDLWindow, SDL_TRUE);end; procedure TForm1.ShutdownSDL;begin   if CurrentTexture <> nil then    SDL_DestroyTexture(CurrentTexture);  if SDLRenderer <> nil then    SDL_DestroyRenderer(SDLRenderer);  if SDLWindow <> nil then    SDL_DestroyWindow(SDLWindow);  IMG_Quit;  SDL_Quit;end; procedure TForm1.RenderImage;var  DstRect: TSDL_Rect;  ImgWidth, ImgHeight, PanelWidth, PanelHeight: Integer;  AspectRatio: Double;begin  if CurrentTexture = nil then Exit;   // Get image dimensions  SDL_QueryTexture(CurrentTexture, nil, nil, @ImgWidth, @ImgHeight);   // Get panel dimensions  PanelWidth := Panel1.Width;  PanelHeight := Panel1.Height;   // Calculate aspect ratio to fit the image proportionally  AspectRatio := Min(PanelWidth / ImgWidth, PanelHeight / ImgHeight);   DstRect.w := Round(ImgWidth * AspectRatio);  DstRect.h := Round(ImgHeight * AspectRatio);  DstRect.x := (PanelWidth - DstRect.w) div 2;  DstRect.y := (PanelHeight - DstRect.h) div 2;   StatusBar1.Panels[0].Text:= IntToStr(ImgWidth) +'x' + inttostr(ImgHeight);   // Render the image  SDL_RenderClear(SDLRenderer);  SDL_RenderCopy(SDLRenderer, CurrentTexture, nil, @DstRect);  SDL_RenderPresent(SDLRenderer);end; procedure TForm1.HandleDropEvent(const FileName: string);begin  LoadAndDisplayImage(FileName);end; procedure TForm1.HandleSDLEvents;var  Event: TSDL_Event;begin  while SDL_PollEvent(@Event) <> 0 do  begin    case Event.type_ of      SDL_DROPFILE:        begin          HandleDropEvent(string(Event.drop.file));          SDL_free(Pointer(Event.drop.file)); // Clean up the file name string      end;      SDL_QUIT:        Close; // Handle quitting the application    end;  end;end; procedure TForm1.LoadAndDisplayImage(const FileName: string);begin   // Clean up the old texture if it exists  if CurrentTexture <> nil then    SDL_DestroyTexture(CurrentTexture);   // Load the new image as a texture  CurrentTexture := IMG_LoadTexture(SDLRenderer, PChar(FileName));  if CurrentTexture = nil then    raise Exception.Create('Nie udało się wczytać tekstury: ' + IMG_GetError);   // Render the image to fit the new size  RenderImage;end; procedure TForm1.FormShow(Sender: TObject);begin   InitializeSDL;end; procedure TForm1.Panel1Paint(Sender: TObject);begin  // Draw a red rectangle (example)  SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255);  SDL_RenderFillRect(sdlRenderer, nil); // Full screen fill  SDL_RenderPresent(sdlRenderer);    RenderImage;end; procedure TForm1.FormDestroy(Sender: TObject);begin  ShutdownSDL;end; procedure TForm1.Button1Click(Sender: TObject);begin  if OpenDialog1.Execute then    begin      LoadAndDisplayImage(OpenDialog1.FileName);    end;end; procedure TForm1.FormResize(Sender: TObject);begin  RenderImage;end;  end.   Regards ---------------------------------------------------------------------- korba812 · 2024-11-20 23:46 "file" is reserved word in pascal. To use a reserved word as an identifier precede it with "&". Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i HandleDropEvent(string(Event.drop.&file)); ---------------------------------------------------------------------- Pe3s · 2024-11-21 07:55 I corrected the code but unfortunately it doesn't work maybe the sdl window doesn't support file dropping? Pascal headers downloaded https://github.com/ev1313/Pascal-SDL-2-Headers Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.HandleSDLEvents;var  Event: TSDL_Event;begin  while SDL_PollEvent(@Event) <> 0 do  begin    case Event.type_ of      SDL_DROPFILE:        begin          HandleDropEvent(string(Event.drop.&file));          SDL_free(Pointer(Event.drop.&file)); // Clean up the file name string        end;      SDL_QUIT:        Close; // Handle quitting the application    end;  end;end;         Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit1.pas(125,45) Error: identifier idents no member "file"unit1.pas(126,39) Error: identifier idents no member "file"unit1.pas(128,15) Error: Constant and CASE types do not matchunit1.pas(128,15) Error: Constant Expression expected ---------------------------------------------------------------------- korba812 · 2024-11-21 09:59 Looking at the sources you provided, this field is named "_file": https://github.com/ev1313/Pascal-SDL-2- Headers/blob/201a767368020183b9964983d1c57ac4bd6a16fd/sdlevents.inc#L4 38 ---------------------------------------------------------------------- Pe3s · 2024-11-21 12:24 I changed it but now there is an error SDL_QUIT: and it doesn't load the image The code appears to be correct I would like to learn SDL and drag and drop Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  unit1.pas(132,17) Error: Constant and CASE types do not matchunit1.pas(132,17) Error: Constant Expression expected  Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  Event: TSDL_Event;begin  while SDL_PollEvent(@Event) <> 0 do  begin    case Event.type_ of      SDL_DROPFILE:        begin          HandleDropEvent(string(Event.drop._file));          SDL_free(Pointer(Event.drop._file)); // Clean up the file name string        end;      SDL_QUIT:        Close; // Handle quitting the application    end;  end;end; ---------------------------------------------------------------------- korba812 · 2024-11-21 12:47 Again looking at code I conclude that you should use constant "SDL_QUITEV" instead of "SDL_QUIT": https://github.com/ev1313/Pascal-SDL-2- Headers/blob/201a767368020183b9964983d1c57ac4bd6a16fd/sdlevents.inc#L5 17C7-L517C17 ---------------------------------------------------------------------- Pe3s · 2024-11-21 16:07 How should I improve the procedure to make dropping files work, because when I drop a file nothing happens. ---------------------------------------------------------------------- Pe3s · 2024-11-21 21:43 I corrected the code but drag and drop doesn't work, it doesn't open the image when it is dropped on the window. What am I doing wrong that this function doesn't work? Allow drop files does nothing Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ComCtrls, ExtCtrls,  StdCtrls, SDL2, SDL2_image, Math; type   { TForm1 }   TForm1 = class(TForm)    Button1: TButton;    OpenDialog1: TOpenDialog;    Panel1: TPanel;    Panel2: TPanel;    StatusBar1: TStatusBar;    procedure Button1Click(Sender: TObject);    procedure FormDestroy(Sender: TObject);    procedure FormResize(Sender: TObject);    procedure FormShow(Sender: TObject);    procedure Panel1Paint(Sender: TObject);  private      SDLWindow: PSDL_Window;      SDLRenderer: PSDL_Renderer;      CurrentTexture: PSDL_Texture;      procedure InitializeSDL;      procedure ShutdownSDL;      procedure LoadAndDisplayImage(const FileName: string);      procedure RenderImage;      procedure HandleDropEvent(const FilePath: string);      procedure ProcessSDLEvents;   public   end; var  Form1: TForm1;   SDLEvent: TSDL_Event; implementation {$R *.lfm} { TForm1 } procedure TForm1.InitializeSDL;begin  if SDL_Init(SDL_INIT_VIDEO) < 0 then    raise Exception.Create('Unable to initialize SDL: ' + SDL_GetError);   // Ensure Panel1.Handle is correctly cast to a pointer  SDLWindow := SDL_CreateWindowFrom(Pointer(Panel1.Handle));  if SDLWindow = nil then    raise Exception.Create('Unable to create SDL window: ' + SDL_GetError);   // Create the renderer  SDLRenderer := SDL_CreateRenderer(SDLWindow, -1, SDL_RENDERER_ACCELERATED or SDL_RENDERER_PRESENTVSYNC);  if SDLRenderer = nil then    raise Exception.Create('Unable to create SDL renderer: ' + SDL_GetError);   // Enable SDL's drop events  SDL_EventState(SDL_DROPFILE, SDL_ENABLE);end; procedure TForm1.ShutdownSDL;begin   if CurrentTexture <> nil then    SDL_DestroyTexture(CurrentTexture);  if SDLRenderer <> nil then    SDL_DestroyRenderer(SDLRenderer);  if SDLWindow <> nil then    SDL_DestroyWindow(SDLWindow);  IMG_Quit;  SDL_Quit;end; procedure TForm1.RenderImage;var  DstRect: TSDL_Rect;  ImgWidth, ImgHeight, PanelWidth, PanelHeight: Integer;  AspectRatio: Double;begin  if CurrentTexture = nil then Exit;   // Get image dimensions  SDL_QueryTexture(CurrentTexture, nil, nil, @ImgWidth, @ImgHeight);   // Get panel dimensions  PanelWidth := Panel1.Width;  PanelHeight := Panel1.Height;   // Calculate aspect ratio to fit the image proportionally  AspectRatio := Min(PanelWidth / ImgWidth, PanelHeight / ImgHeight);   DstRect.w := Round(ImgWidth * AspectRatio);  DstRect.h := Round(ImgHeight * AspectRatio);  DstRect.x := (PanelWidth - DstRect.w) div 2;  DstRect.y := (PanelHeight - DstRect.h) div 2;   StatusBar1.Panels[0].Text:= IntToStr(ImgWidth) +'x' + inttostr(ImgHeight);   // Render the image  SDL_RenderClear(SDLRenderer);  SDL_RenderCopy(SDLRenderer, CurrentTexture, nil, @DstRect);  SDL_RenderPresent(SDLRenderer);end; procedure TForm1.HandleDropEvent(const FilePath: string);begin  // Load and display the dropped image file  if FileExists(FilePath) then  begin  LoadAndDisplayImage(FilePath);    Form1.Caption := 'Loaded: ' + ExtractFileName(FilePath);  end  else    ShowMessage('Invalid file dropped: ' + FilePath);end; procedure TForm1.ProcessSDLEvents;begin  while SDL_PollEvent(@SDLEvent) <> 0 do  begin    case SDLEvent.type_ of      SDL_DROPFILE:        begin          HandleDropEvent(SDLEvent.drop._file);          SDL_free(SDLEvent.drop._file); // Free the file path allocated by SDL        end;      SDL_QUITEV:        begin          Close;        end;  end;  end;end; procedure TForm1.LoadAndDisplayImage(const FileName: string);begin   // Clean up the old texture if it exists  if CurrentTexture <> nil then    SDL_DestroyTexture(CurrentTexture);   // Load the new image as a texture  CurrentTexture := IMG_LoadTexture(SDLRenderer, PChar(FileName));  if CurrentTexture = nil then    raise Exception.Create('Nie udało się wczytać tekstury: ' + IMG_GetError);   // Render the image to fit the new size  RenderImage;end; procedure TForm1.FormShow(Sender: TObject);begin   InitializeSDL; end; procedure TForm1.Panel1Paint(Sender: TObject);begin  // Draw a red rectangle (example)  SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255);  SDL_RenderFillRect(sdlRenderer, nil); // Full screen fill  SDL_RenderPresent(sdlRenderer);    RenderImage;end; procedure TForm1.FormDestroy(Sender: TObject);begin  ShutdownSDL;end; procedure TForm1.Button1Click(Sender: TObject);begin  if OpenDialog1.Execute then    begin      LoadAndDisplayImage(OpenDialog1.FileName);    end;end; procedure TForm1.FormResize(Sender: TObject);begin   RenderImage;end;  end. ---------------------------------------------------------------------- TRon · 2024-11-22 00:35 Quote from: Pe3s on November 21, 2024, 10:43:23 pmWhat am I doing wrong that this function doesn't work? It has been a while when working with SDL but let's give it a try  The concept of what you are trying to do does not compute. SDL events are processed inside a SDL event loop. GUI events are processed inside the GUI message-loop. These two conflict. In fact, the example-code never actually processes the SDL events. Either use the drag and drop functionality of Lazarus or change the concept as a whole. ---------------------------------------------------------------------- Pe3s · 2024-11-22 07:23 The drag and drop function from Lazarus does not work from the SDL window. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.FormDropFiles(Sender: TObject; const FileNames: array of string);var  i: Integer;begin  for i := Low(FileNames) to High(FileNames) do     LoadAndDisplayImage(FileNames[i]);end; ---------------------------------------------------------------------- Pe3s · 2024-11-22 08:33 How can I combine sdl and lcl so that the drop function also works with the sdl window ---------------------------------------------------------------------- TRon · 2024-11-22 08:57 Quote from: Pe3s on November 22, 2024, 08:23:57 amThe drag and drop function from Lazarus does not work from the SDL window. I am confused about what you meant by that. Are you trying to drag from the sdl window to the lazarus form or something like that perhaps ? The hist that I got from your original code is that you want to be able to drag files from the OS and drop to your SDL window, in which case Lazarus LCL should take care of the drop and in the event handler you do whatever you do with the dropped file name (instead of SDL handling the event). Quote from: Pe3s on November 22, 2024, 09:33:37 amHow can I combine sdl and lcl so that the drop function also works with the sdl window As described above. It is either that or translate either all(*) SDL events to LCL or all(*) LCL events to SDL. Neither one is something that is easily realized. (*) with all I mean all events that you are interested in and/or need to take care of. That is why I wrote the concept that you are using in your approach as per your example does not compute as it would require two event loops to be running parallel. In theory that is solvable with running f.e. your SDL event loop inside a thread but as per your example that  would (only) complicate matters further. How you would need to solve the issue depends entirely on your end- goal which also means that you need to decide whether you want LCL or SDL to handle things. Perhaps you could have a look at the Lazarus GL controls and how things are solved there. Unfortunately I am unable to provide details because I'm on Linux and passing a LCL handle to SDL using GTK does not compute (and the LCL- foo seem to fail me atm). ---------------------------------------------------------------------- Pe3s · 2024-11-22 09:11 This sdl code should handle file dropping. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.HandleSDLEvents;var  Event: TSDL_Event;begin  while SDL_PollEvent(@Event) <> 0 do  begin    case Event.type_ of      SDL_DROPFILE:        begin          HandleDropEvent(string(Event.drop.file));          SDL_free(Pointer(Event.drop.file)); // Clean up the file name string      end;      SDL_QUIT:        Close; // Handle quitting the application    end;  end;end; ---------------------------------------------------------------------- Seenkao · 2024-11-22 11:01 Quote from: Pe3s on November 22, 2024, 09:33:37 amHow can I combine sdl and lcl so that the drop function also works with the sdl window Что именно вы хотите переместить? 1. Если вы с помощью SDL создали графическую область (context) в одной форме и хотите переместить на другой контекст, созданный на другой форме, то это делается только вручную. Если только сам SDL не предоставляет возможностей копирования данных из одного контекста в другой. 2. Если вы хотите скопировать из созданного контекста на одной форме, в другую LCL-форму, то это так же придётся делать вручную. 3. Если вы хотите что-то скопировать из одной формы в другую, то тут, на форуме, вам смогут помочь. -------------------------------------------------------- Google translate: What exactly do you want to move? 1. If you created a graphic area (context) in one form using SDL and want to move it to another context created on another form, then this can only be done manually. Unless SDL itself provides the ability to copy data from one context to another. 2. If you want to copy from a created context on one form to another LCL form, then this will also have to be done manually. 3. If you want to copy something from one form to another, then here on the forum they can help you. ---------------------------------------------------------------------- Pe3s · 2024-11-22 11:08 I want to make it so that the file can be dragged and dropped onto the SDL window to open the file. ---------------------------------------------------------------------- Pe3s · 2024-11-23 08:47 Why is there a function “ SDL_DROPFILE” as it does not work. And if it works there is no example of correct usage. ---------------------------------------------------------------------- jamie · 2024-11-23 15:38 Shooting from the hip, because I am stupid, have you tried enabling the "AllowDropFiles" in the form? Jamie ---------------------------------------------------------------------- TRon · 2024-11-23 15:47 @Jamie: That wouldn't help in any way. The SDL eventloop is never ran. @Pe3s: Normally SDL creates its own window and takes responsibility for 'catching' the events that are generated from the 'outside'. Because the SDL window is embedded in a LCL control SDL is not able to take care of that unless running in a SDL eventloop (again: a loop that is never ran). So, use the form drag and drop events. Anything else is just pure speculation because there is no description of what the end-goal actually is. As I wrote before, the concept of your solution simply does not compute. And no matter what, either using form events or SDL events the code still needs to handle those events and actually do something with the filename. It does not matter where that exactly is done (in SDL or LCL). In basics the SDL in the panel right now is nothing more than a glorified image control and should be treated the same. ---------------------------------------------------------------------- Pe3s · 2024-11-23 15:56 I want to open the dropped file as it is done via open dialog. the sdl window does not support dropping files. OnDropFiles of Lazarus. If we drop them on the form, they load, but most of the window is occupied by the sdl window. The matter would be simple if the sdl window inherited the lcl event handler ---------------------------------------------------------------------- jamie · 2024-11-23 15:59 Ok, I know in windows you need to register the window handle for it to receive drop file notifications. In other targets, I have no idea. ---------------------------------------------------------------------- TRon · 2024-11-23 16:01 Quote from: Pe3s on November 23, 2024, 04:56:55 pmThe matter would be simple if the sdl window inherited the lcl event handler Yes, that would solve it but SDL doesn't (how could it ?). As a test you could try an use the onidle event of the application to run your SDL event poll and see if SDL at least generates the event. In case that doesn't work then the only way that I know of is to use the form events and handling things manually. ---------------------------------------------------------------------- jamie · 2024-11-23 16:16 Last time I remember, those Messages from the OS in windows are blocked and only the embedded support for the drag and drop that the LCL works because it's handled elsewhere to allow it. But basically, they are blocked thus you need to actually hook into the message event to see it.  I've ported over code from Delphi doing Drag and Drop and wouldn't work in the LCL because of these messages being blocked and had to resort to hooking it.  I do have a unit to make it easy to insert blocked messages for the form but its only for the LCL/Laz because Delphi does not have this issue.  Have a good day. Jamie ---------------------------------------------------------------------- TRon · 2024-11-23 16:20 Indeed, something like that should be able to do the trick jamie. However these kind of things are usually not for the casual user. There is a reason I hinted at having a look at the gl controls because they need to do something similar and based on that one could probably come up with an embedded SDL control (in case it doesn't exist yet). ---------------------------------------------------------------------- jamie · 2024-11-23 17:14 On the windows side of things, it's possible the whole thing is blocked and even the LCL support may not work if you have one these conditions. https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf- winuser-changewindowmessagefilterex  This also has something to do with app elevations permissions. Jamie ---------------------------------------------------------------------- Pe3s · 2024-11-24 08:19 Thank you for your help in solving the problem. Application.OnIdle solved the problem Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.ApplicationIdle(Sender: TObject; var Done: Boolean);begin  ProcessSDLEvents;  Done := False;end;  Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.FormShow(Sender: TObject);begin  InitializeSDL;  Application.OnIdle := @ApplicationIdle;end;  Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.FormDestroy(Sender: TObject);begin  Application.OnIdle := nil;  ShutdownSDL;end;