Recent

Author Topic: SDL2 drag and drop image [SOLVED]  (Read 2473 times)

Pe3s

  • Hero Member
  • *****
  • Posts: 590
SDL2 drag and drop image [SOLVED]
« on: November 20, 2024, 11:32:40 pm »
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][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ComCtrls, ExtCtrls,
  9.   StdCtrls, SDL2, SDL2_image, Math;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     OpenDialog1: TOpenDialog;
  18.     Panel1: TPanel;
  19.     Panel2: TPanel;
  20.     StatusBar1: TStatusBar;
  21.     procedure Button1Click(Sender: TObject);
  22.     procedure FormDestroy(Sender: TObject);
  23.     procedure FormResize(Sender: TObject);
  24.     procedure FormShow(Sender: TObject);
  25.     procedure Panel1Paint(Sender: TObject);
  26.   private
  27.       SDLWindow: PSDL_Window;
  28.       SDLRenderer: PSDL_Renderer;
  29.       CurrentTexture: PSDL_Texture;
  30.       procedure InitializeSDL;
  31.       procedure ShutdownSDL;
  32.       procedure LoadAndDisplayImage(const FileName: string);
  33.       procedure RenderImage;
  34.       procedure HandleDropEvent(const FileName: string);
  35.       procedure HandleSDLEvents;
  36.  
  37.   public
  38.  
  39.   end;
  40.  
  41. var
  42.   Form1: TForm1;
  43.  
  44. implementation
  45.  
  46. {$R *.lfm}
  47.  
  48. { TForm1 }
  49.  
  50. procedure TForm1.InitializeSDL;
  51. begin
  52.   if SDL_Init(SDL_INIT_VIDEO) < 0 then
  53.     raise Exception.Create('Nie udało się zainicjować SDL: ' + SDL_GetError);
  54.  
  55.   SDLWindow := SDL_CreateWindowFrom(Pointer(Panel1.Handle));
  56.   if SDLWindow = nil then
  57.     raise Exception.Create('Nie udało się utworzyć okna SDL: ' + SDL_GetError);
  58.  
  59.   SDLRenderer := SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED or SDL_RENDERER_PRESENTVSYNC);;
  60.   if SDLRenderer = nil then
  61.     raise Exception.Create('Nie można utworzyć renderowania SDL: ' + SDL_GetError);
  62.  
  63.      // Enable the drag-and-drop feature
  64.   SDL_SetWindowGrab(SDLWindow, SDL_TRUE);
  65. end;
  66.  
  67. procedure TForm1.ShutdownSDL;
  68. begin
  69.    if CurrentTexture <> nil then
  70.     SDL_DestroyTexture(CurrentTexture);
  71.   if SDLRenderer <> nil then
  72.     SDL_DestroyRenderer(SDLRenderer);
  73.   if SDLWindow <> nil then
  74.     SDL_DestroyWindow(SDLWindow);
  75.   IMG_Quit;
  76.   SDL_Quit;
  77. end;
  78.  
  79. procedure TForm1.RenderImage;
  80. var
  81.   DstRect: TSDL_Rect;
  82.   ImgWidth, ImgHeight, PanelWidth, PanelHeight: Integer;
  83.   AspectRatio: Double;
  84. begin
  85.   if CurrentTexture = nil then Exit;
  86.  
  87.   // Get image dimensions
  88.   SDL_QueryTexture(CurrentTexture, nil, nil, @ImgWidth, @ImgHeight);
  89.  
  90.   // Get panel dimensions
  91.   PanelWidth := Panel1.Width;
  92.   PanelHeight := Panel1.Height;
  93.  
  94.   // Calculate aspect ratio to fit the image proportionally
  95.   AspectRatio := Min(PanelWidth / ImgWidth, PanelHeight / ImgHeight);
  96.  
  97.   DstRect.w := Round(ImgWidth * AspectRatio);
  98.   DstRect.h := Round(ImgHeight * AspectRatio);
  99.   DstRect.x := (PanelWidth - DstRect.w) div 2;
  100.   DstRect.y := (PanelHeight - DstRect.h) div 2;
  101.  
  102.   StatusBar1.Panels[0].Text:= IntToStr(ImgWidth) +'x' + inttostr(ImgHeight);
  103.  
  104.   // Render the image
  105.   SDL_RenderClear(SDLRenderer);
  106.   SDL_RenderCopy(SDLRenderer, CurrentTexture, nil, @DstRect);
  107.   SDL_RenderPresent(SDLRenderer);
  108. end;
  109.  
  110. procedure TForm1.HandleDropEvent(const FileName: string);
  111. begin
  112.   LoadAndDisplayImage(FileName);
  113. end;
  114.  
  115. procedure TForm1.HandleSDLEvents;
  116. var
  117.   Event: TSDL_Event;
  118. begin
  119.   while SDL_PollEvent(@Event) <> 0 do
  120.   begin
  121.     case Event.type_ of
  122.       SDL_DROPFILE:
  123.         begin
  124.           HandleDropEvent(string(Event.drop.file));
  125.           SDL_free(Pointer(Event.drop.file)); // Clean up the file name string
  126.         end;
  127.       SDL_QUIT:
  128.         Close; // Handle quitting the application
  129.     end;
  130.   end;
  131. end;
  132.  
  133. procedure TForm1.LoadAndDisplayImage(const FileName: string);
  134. begin
  135.    // Clean up the old texture if it exists
  136.   if CurrentTexture <> nil then
  137.     SDL_DestroyTexture(CurrentTexture);
  138.  
  139.   // Load the new image as a texture
  140.   CurrentTexture := IMG_LoadTexture(SDLRenderer, PChar(FileName));
  141.   if CurrentTexture = nil then
  142.     raise Exception.Create('Nie udało się wczytać tekstury: ' + IMG_GetError);
  143.  
  144.   // Render the image to fit the new size
  145.   RenderImage;
  146. end;
  147.  
  148. procedure TForm1.FormShow(Sender: TObject);
  149. begin
  150.    InitializeSDL;
  151. end;
  152.  
  153. procedure TForm1.Panel1Paint(Sender: TObject);
  154. begin
  155.   // Draw a red rectangle (example)
  156.   SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255);
  157.   SDL_RenderFillRect(sdlRenderer, nil); // Full screen fill
  158.   SDL_RenderPresent(sdlRenderer);
  159.  
  160.    RenderImage;
  161. end;
  162.  
  163. procedure TForm1.FormDestroy(Sender: TObject);
  164. begin
  165.   ShutdownSDL;
  166. end;
  167.  
  168. procedure TForm1.Button1Click(Sender: TObject);
  169. begin
  170.   if OpenDialog1.Execute then
  171.     begin
  172.       LoadAndDisplayImage(OpenDialog1.FileName);
  173.     end;
  174. end;
  175.  
  176. procedure TForm1.FormResize(Sender: TObject);
  177. begin
  178.   RenderImage;
  179. end;
  180.  
  181.  
  182. end.
  183.  
  184.  

Regards
« Last Edit: November 24, 2024, 09:21:37 am by Pe3s »

korba812

  • Sr. Member
  • ****
  • Posts: 446
Re: SDL2 drag and drop image
« Reply #1 on: November 21, 2024, 12:46:19 am »
"file" is reserved word in pascal. To use a reserved word as an identifier precede it with "&".
Code: Pascal  [Select][+][-]
  1. HandleDropEvent(string(Event.drop.&file));

Pe3s

  • Hero Member
  • *****
  • Posts: 590
Re: SDL2 drag and drop image
« Reply #2 on: November 21, 2024, 08:55:02 am »
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][+][-]
  1. procedure TForm1.HandleSDLEvents;
  2. var
  3.   Event: TSDL_Event;
  4. begin
  5.   while SDL_PollEvent(@Event) <> 0 do
  6.   begin
  7.     case Event.type_ of
  8.       SDL_DROPFILE:
  9.         begin
  10.           HandleDropEvent(string(Event.drop.&file));
  11.           SDL_free(Pointer(Event.drop.&file)); // Clean up the file name string
  12.         end;
  13.       SDL_QUIT:
  14.         Close; // Handle quitting the application
  15.     end;
  16.   end;
  17. end;        
  18.  
Code: Pascal  [Select][+][-]
  1. unit1.pas(125,45) Error: identifier idents no member "file"
  2. unit1.pas(126,39) Error: identifier idents no member "file"
  3. unit1.pas(128,15) Error: Constant and CASE types do not match
  4. unit1.pas(128,15) Error: Constant Expression expected
« Last Edit: November 21, 2024, 10:41:34 am by Pe3s »

korba812

  • Sr. Member
  • ****
  • Posts: 446
Re: SDL2 drag and drop image
« Reply #3 on: November 21, 2024, 10:59:34 am »

Pe3s

  • Hero Member
  • *****
  • Posts: 590
Re: SDL2 drag and drop image
« Reply #4 on: November 21, 2024, 01:24:21 pm »
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][+][-]
  1.  
  2. unit1.pas(132,17) Error: Constant and CASE types do not match
  3. unit1.pas(132,17) Error: Constant Expression expected
  4.  
  5.  
Code: Pascal  [Select][+][-]
  1. var
  2.   Event: TSDL_Event;
  3. begin
  4.   while SDL_PollEvent(@Event) <> 0 do
  5.   begin
  6.     case Event.type_ of
  7.       SDL_DROPFILE:
  8.         begin
  9.           HandleDropEvent(string(Event.drop._file));
  10.           SDL_free(Pointer(Event.drop._file)); // Clean up the file name string
  11.         end;
  12.       SDL_QUIT:
  13.         Close; // Handle quitting the application
  14.     end;
  15.   end;
  16. end;            

korba812

  • Sr. Member
  • ****
  • Posts: 446
Re: SDL2 drag and drop image
« Reply #5 on: November 21, 2024, 01:47:05 pm »
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#L517C7-L517C17

Pe3s

  • Hero Member
  • *****
  • Posts: 590
Re: SDL2 drag and drop image
« Reply #6 on: November 21, 2024, 05:07:08 pm »
How should I improve the procedure to make dropping files work, because when I drop a file nothing happens.

Pe3s

  • Hero Member
  • *****
  • Posts: 590
Re: SDL2 drag and drop image
« Reply #7 on: November 21, 2024, 10:43:23 pm »
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][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ComCtrls, ExtCtrls,
  9.   StdCtrls, SDL2, SDL2_image, Math;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     OpenDialog1: TOpenDialog;
  18.     Panel1: TPanel;
  19.     Panel2: TPanel;
  20.     StatusBar1: TStatusBar;
  21.     procedure Button1Click(Sender: TObject);
  22.     procedure FormDestroy(Sender: TObject);
  23.     procedure FormResize(Sender: TObject);
  24.     procedure FormShow(Sender: TObject);
  25.     procedure Panel1Paint(Sender: TObject);
  26.   private
  27.       SDLWindow: PSDL_Window;
  28.       SDLRenderer: PSDL_Renderer;
  29.       CurrentTexture: PSDL_Texture;
  30.       procedure InitializeSDL;
  31.       procedure ShutdownSDL;
  32.       procedure LoadAndDisplayImage(const FileName: string);
  33.       procedure RenderImage;
  34.       procedure HandleDropEvent(const FilePath: string);
  35.       procedure ProcessSDLEvents;
  36.  
  37.   public
  38.  
  39.   end;
  40.  
  41. var
  42.   Form1: TForm1;
  43.    SDLEvent: TSDL_Event;
  44.  
  45. implementation
  46.  
  47. {$R *.lfm}
  48.  
  49. { TForm1 }
  50.  
  51. procedure TForm1.InitializeSDL;
  52. begin
  53.   if SDL_Init(SDL_INIT_VIDEO) < 0 then
  54.     raise Exception.Create('Unable to initialize SDL: ' + SDL_GetError);
  55.  
  56.   // Ensure Panel1.Handle is correctly cast to a pointer
  57.   SDLWindow := SDL_CreateWindowFrom(Pointer(Panel1.Handle));
  58.   if SDLWindow = nil then
  59.     raise Exception.Create('Unable to create SDL window: ' + SDL_GetError);
  60.  
  61.   // Create the renderer
  62.   SDLRenderer := SDL_CreateRenderer(SDLWindow, -1, SDL_RENDERER_ACCELERATED or SDL_RENDERER_PRESENTVSYNC);
  63.   if SDLRenderer = nil then
  64.     raise Exception.Create('Unable to create SDL renderer: ' + SDL_GetError);
  65.  
  66.   // Enable SDL's drop events
  67.   SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
  68. end;
  69.  
  70. procedure TForm1.ShutdownSDL;
  71. begin
  72.    if CurrentTexture <> nil then
  73.     SDL_DestroyTexture(CurrentTexture);
  74.   if SDLRenderer <> nil then
  75.     SDL_DestroyRenderer(SDLRenderer);
  76.   if SDLWindow <> nil then
  77.     SDL_DestroyWindow(SDLWindow);
  78.   IMG_Quit;
  79.   SDL_Quit;
  80. end;
  81.  
  82. procedure TForm1.RenderImage;
  83. var
  84.   DstRect: TSDL_Rect;
  85.   ImgWidth, ImgHeight, PanelWidth, PanelHeight: Integer;
  86.   AspectRatio: Double;
  87. begin
  88.   if CurrentTexture = nil then Exit;
  89.  
  90.   // Get image dimensions
  91.   SDL_QueryTexture(CurrentTexture, nil, nil, @ImgWidth, @ImgHeight);
  92.  
  93.   // Get panel dimensions
  94.   PanelWidth := Panel1.Width;
  95.   PanelHeight := Panel1.Height;
  96.  
  97.   // Calculate aspect ratio to fit the image proportionally
  98.   AspectRatio := Min(PanelWidth / ImgWidth, PanelHeight / ImgHeight);
  99.  
  100.   DstRect.w := Round(ImgWidth * AspectRatio);
  101.   DstRect.h := Round(ImgHeight * AspectRatio);
  102.   DstRect.x := (PanelWidth - DstRect.w) div 2;
  103.   DstRect.y := (PanelHeight - DstRect.h) div 2;
  104.  
  105.   StatusBar1.Panels[0].Text:= IntToStr(ImgWidth) +'x' + inttostr(ImgHeight);
  106.  
  107.   // Render the image
  108.   SDL_RenderClear(SDLRenderer);
  109.   SDL_RenderCopy(SDLRenderer, CurrentTexture, nil, @DstRect);
  110.   SDL_RenderPresent(SDLRenderer);
  111. end;
  112.  
  113. procedure TForm1.HandleDropEvent(const FilePath: string);
  114. begin
  115.   // Load and display the dropped image file
  116.   if FileExists(FilePath) then
  117.   begin
  118.     LoadAndDisplayImage(FilePath);
  119.     Form1.Caption := 'Loaded: ' + ExtractFileName(FilePath);
  120.   end
  121.   else
  122.     ShowMessage('Invalid file dropped: ' + FilePath);
  123. end;
  124.  
  125. procedure TForm1.ProcessSDLEvents;
  126. begin
  127.   while SDL_PollEvent(@SDLEvent) <> 0 do
  128.   begin
  129.     case SDLEvent.type_ of
  130.       SDL_DROPFILE:
  131.         begin
  132.           HandleDropEvent(SDLEvent.drop._file);
  133.           SDL_free(SDLEvent.drop._file); // Free the file path allocated by SDL
  134.         end;
  135.       SDL_QUITEV:
  136.         begin
  137.           Close;
  138.         end;
  139.     end;
  140.   end;
  141. end;
  142.  
  143. procedure TForm1.LoadAndDisplayImage(const FileName: string);
  144. begin
  145.    // Clean up the old texture if it exists
  146.   if CurrentTexture <> nil then
  147.     SDL_DestroyTexture(CurrentTexture);
  148.  
  149.   // Load the new image as a texture
  150.   CurrentTexture := IMG_LoadTexture(SDLRenderer, PChar(FileName));
  151.   if CurrentTexture = nil then
  152.     raise Exception.Create('Nie udało się wczytać tekstury: ' + IMG_GetError);
  153.  
  154.   // Render the image to fit the new size
  155.   RenderImage;
  156. end;
  157.  
  158. procedure TForm1.FormShow(Sender: TObject);
  159. begin
  160.    InitializeSDL;
  161.  
  162. end;
  163.  
  164. procedure TForm1.Panel1Paint(Sender: TObject);
  165. begin
  166.   // Draw a red rectangle (example)
  167.   SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255);
  168.   SDL_RenderFillRect(sdlRenderer, nil); // Full screen fill
  169.   SDL_RenderPresent(sdlRenderer);
  170.  
  171.    RenderImage;
  172. end;
  173.  
  174. procedure TForm1.FormDestroy(Sender: TObject);
  175. begin
  176.   ShutdownSDL;
  177. end;
  178.  
  179. procedure TForm1.Button1Click(Sender: TObject);
  180. begin
  181.   if OpenDialog1.Execute then
  182.     begin
  183.       LoadAndDisplayImage(OpenDialog1.FileName);
  184.     end;
  185. end;
  186.  
  187. procedure TForm1.FormResize(Sender: TObject);
  188. begin
  189.  
  190.   RenderImage;
  191. end;
  192.  
  193.  
  194. end.
  195.  
  196.  
« Last Edit: November 21, 2024, 10:45:36 pm by Pe3s »

TRon

  • Hero Member
  • *****
  • Posts: 3788
Re: SDL2 drag and drop image
« Reply #8 on: November 22, 2024, 01:35:28 am »
What 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.
I do not have to remember anything anymore thanks to total-recall.

Pe3s

  • Hero Member
  • *****
  • Posts: 590
Re: SDL2 drag and drop image
« Reply #9 on: November 22, 2024, 08:23:57 am »
The drag and drop function from Lazarus does not work from the SDL window.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormDropFiles(Sender: TObject; const FileNames: array of string);
  2. var
  3.   i: Integer;
  4. begin
  5.   for i := Low(FileNames) to High(FileNames) do
  6.      LoadAndDisplayImage(FileNames[i]);
  7. end;
  8.  

Pe3s

  • Hero Member
  • *****
  • Posts: 590
Re: SDL2 drag and drop image
« Reply #10 on: November 22, 2024, 09:33:37 am »
How can I combine sdl and lcl so that the drop function also works with the sdl window

TRon

  • Hero Member
  • *****
  • Posts: 3788
Re: SDL2 drag and drop image
« Reply #11 on: November 22, 2024, 09:57:16 am »
The 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).

How 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).
I do not have to remember anything anymore thanks to total-recall.

Pe3s

  • Hero Member
  • *****
  • Posts: 590
Re: SDL2 drag and drop image
« Reply #12 on: November 22, 2024, 10:11:02 am »
This sdl code should handle file dropping.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.HandleSDLEvents;
  2. var
  3.   Event: TSDL_Event;
  4. begin
  5.   while SDL_PollEvent(@Event) <> 0 do
  6.   begin
  7.     case Event.type_ of
  8.       SDL_DROPFILE:
  9.         begin
  10.           HandleDropEvent(string(Event.drop.file));
  11.           SDL_free(Pointer(Event.drop.file)); // Clean up the file name string
  12.         end;
  13.       SDL_QUIT:
  14.         Close; // Handle quitting the application
  15.     end;
  16.   end;
  17. end;
  18.  

Seenkao

  • Hero Member
  • *****
  • Posts: 649
    • New ZenGL.
Re: SDL2 drag and drop image
« Reply #13 on: November 22, 2024, 12:01:45 pm »
How 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.
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL

Pe3s

  • Hero Member
  • *****
  • Posts: 590
Re: SDL2 drag and drop image
« Reply #14 on: November 22, 2024, 12:08:23 pm »
I want to make it so that the file can be dragged and dropped onto the SDL window to open the file.

 

TinyPortal © 2005-2018