-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgui_interface.pas
More file actions
657 lines (567 loc) · 20.3 KB
/
gui_interface.pas
File metadata and controls
657 lines (567 loc) · 20.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
unit Gui_Interface;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils, raylib, raygui, Init, Math;
// Interface utilisateur
procedure DrawRightPanel(var cutter: TImageCutter);
procedure UpdateGUI(var cutter: TImageCutter);
function LoadImageDialog(): string;
procedure CalculateGrid(var cutter: TImageCutter);
// Gestion des contrôles
procedure HandleKeyboardInput(var cutter: TImageCutter);
procedure HandleMouseInput(var cutter: TImageCutter);
implementation
procedure LoadSpecificImage(var cutter: TImageCutter; filename: string);
begin
with cutter do
begin
WriteLn('Tentative de chargement: ', filename);
if imageLoaded then
begin
UnloadTexture(texture);
WriteLn('Ancienne texture libérée');
end;
texture := LoadTexture(PChar(filename));
if IsTextureValid(texture) then
begin
imageLoaded := True;
imageName := ExtractFileName(filename);
showFileList := False; // Masquer la liste après chargement
// Centrer l'image lors du chargement
imageOffsetX := (screenWidth - rightPanelWidth - texture.width) div 2;
imageOffsetY := (screenHeight - texture.height) div 2;
CalculateGrid(cutter);
WriteLn('Image chargée avec succès: ', imageName);
WriteLn('Dimensions: ', texture.width, 'x', texture.height);
end
else
begin
WriteLn('ERREUR: Impossible de charger la texture');
imageLoaded := False;
end;
end;
end;
function LoadImageDialog(): string;
begin
// Chemin en dur pour les tests
Result := 'ressources/carte1870.png';
// Vérifier que le fichier existe
if not FileExists(pchar(Result)) then
begin
WriteLn('ERREUR: Fichier non trouvé: ', Result);
WriteLn('Formats supportés: PNG, JPG, BMP');
Result := '';
end
else
begin
WriteLn('Fichier trouvé: ', Result);
end;
end;
procedure CalculateGrid(var cutter: TImageCutter);
begin
with cutter do
begin
if not imageLoaded or (grid.rows = 0) or (grid.cols = 0) then
begin
grid.cellWidth := 0;
grid.cellHeight := 0;
Exit;
end;
if fixedSquareMode then
begin
// Mode carré fixe : tous les carrés ont la même taille
grid.cellWidth := squareSize;
grid.cellHeight := squareSize;
WriteLn('Mode carré fixe: ', grid.rows, 'x', grid.cols, ' carrés de ', squareSize, 'px');
end
else
begin
// Mode rectangle adaptatif : diviser l'image
grid.cellWidth := texture.width div grid.cols;
grid.cellHeight := texture.height div grid.rows;
WriteLn('Mode rectangle: cellules ', grid.cellWidth, 'x', grid.cellHeight, 'px');
end;
end;
end;
procedure DrawImageInfo(var cutter: TImageCutter; x, y: Integer);
var
infoY: Integer;
begin
infoY := y;
with cutter do
begin
GuiLabel(RectangleCreate(x, infoY, 180, 20), 'INFORMATIONS IMAGE');
infoY := infoY + 25;
if imageLoaded then
begin
GuiLabel(RectangleCreate(x, infoY, 150, 15),
PChar(Format('Fichier: %s', [imageName])));
infoY := infoY + 20;
GuiLabel(RectangleCreate(x, infoY, 180, 15),
PChar(Format('Taille: %dx%d', [texture.width, texture.height])));
infoY := infoY + 20;
end
else
begin
GuiLabel(RectangleCreate(x, infoY, 180, 15), 'Aucune image chargée');
infoY := infoY + 20;
end;
end;
end;
procedure DrawGridControls(var cutter: TImageCutter; x, y: Integer);
var
controlY: Integer;
spinnerResult: Integer;
newRows, newCols: Integer;
sliderValue: Single;
checkboxResult: Integer;
begin
controlY := y;
with cutter do
begin
GuiLabel(RectangleCreate(x, controlY, 200, 20), 'PARAMÈTRES GRILLE');
controlY := controlY + 30;
// Checkbox mode carré fixe
checkboxResult := GuiCheckBox(RectangleCreate(x, controlY, 15, 15), 'Mode carré fixe', @fixedSquareMode);
if checkboxResult <> 0 then
begin
if fixedSquareMode then
WriteLn('Mode changé: Carré fixe')
else WriteLn('Mode changé:Rectangle adaptatif');
CalculateGrid(cutter);
end;
controlY := controlY + 30;
// Checkbox mode verso
checkboxResult := GuiCheckBox(RectangleCreate(x, controlY, 15, 15), 'Mode verso', @versoMode);
if checkboxResult <> 0 then
begin
if versoMode then
WriteLn('Mode changé: Verso (droite→gauche)')
else
WriteLn('Mode changé: Recto (gauche→droite)');
end;
controlY := controlY + 30;
// Contrôles spécifiques au mode carré fixe
if fixedSquareMode then
begin
// Taille du carré : Slider + Spinner
GuiLabel(RectangleCreate(x, controlY, 100, 15), 'Taille carré:');
controlY := controlY + 20;
// Slider
sliderValue := squareSize;
if GuiSlider(RectangleCreate(x+10, controlY, 150, 15), '10', '200', @sliderValue, 10, 200) <> 0 then
begin
squareSize := Round(sliderValue);
CalculateGrid(cutter);
WriteLn('Taille carré (slider): ', squareSize, 'px');
end;
// Afficher la valeur
GuiLabel(RectangleCreate(x + 200, controlY, 50, 15), PChar(IntToStr(squareSize) + 'px'));
controlY := controlY + 25;
end;
// Contrôle nombre de lignes
if fixedSquareMode then
GuiLabel(RectangleCreate(x, controlY, 80, 15), 'Lignes:')
else
GuiLabel(RectangleCreate(x, controlY, 80, 15), 'Lignes:');
spinnerResult := GuiSpinner(RectangleCreate(x + 85, controlY, 100, 20), '', @grid.rows, 1, 50, False);
if spinnerResult <> 0 then
begin
CalculateGrid(cutter);
WriteLn('Nouvelles lignes: ', grid.rows);
end;
controlY := controlY + 30;
// Contrôle nombre de colonnes
if fixedSquareMode then
GuiLabel(RectangleCreate(x, controlY, 80, 15), 'Colonnes:')
else
GuiLabel(RectangleCreate(x, controlY, 80, 15), 'Colonnes:');
spinnerResult := GuiSpinner(RectangleCreate(x + 85, controlY, 100, 20), '', @grid.cols, 1, 50, False);
if spinnerResult <> 0 then
begin
CalculateGrid(cutter);
WriteLn('Nouvelles colonnes: ', grid.cols);
end;
controlY := controlY + 30;
// Affichage informations calculées
if imageLoaded and (grid.cellWidth > 0) then
begin
if fixedSquareMode then
begin
GuiLabel(RectangleCreate(x, controlY, 180, 15),
PChar(Format('Carrés: %dx%d px', [grid.cellWidth, grid.cellHeight])));
controlY := controlY + 20;
GuiLabel(RectangleCreate(x, controlY, 180, 15),
PChar(Format('Total carrés: %d', [grid.rows * grid.cols])));
controlY := controlY + 20;
GuiLabel(RectangleCreate(x, controlY, 180, 15),
PChar(Format('Grille: %dx%d px', [grid.cols * squareSize, grid.rows * squareSize])));
controlY := controlY + 25;
end
else
begin
GuiLabel(RectangleCreate(x, controlY, 180, 15),
PChar(Format('Taille cellules: %dx%d', [grid.cellWidth, grid.cellHeight])));
controlY := controlY + 20;
GuiLabel(RectangleCreate(x, controlY, 180, 15),
PChar(Format('Total cellules: %d', [grid.rows * grid.cols])));
controlY := controlY + 25;
end;
end;
end;
end;
procedure DrawFileControls(var cutter: TImageCutter; x, y: Integer);
var
controlY: Integer;
textboxResult: Integer;
exampleText: string;
begin
controlY := y-100;
with cutter do
begin
GuiLabel(RectangleCreate(x, controlY, 150, 20), 'FICHIERS');
controlY := controlY + 30;
// Préfixe des fichiers - APPROCHE GLOBALE
GuiLabel(RectangleCreate(x, controlY, 150, 15), 'Préfixe:');
controlY := controlY + 20;
// Initialiser le buffer une seule fois
SyncPrefixToBuffer(cutter);
// Utiliser le buffer global directement
textboxResult := GuiTextBox(RectangleCreate(x, controlY, 120, 20), prefixBuffer, 64, True);
// Synchroniser le buffer vers la string si modifié
if textboxResult <> 0 then
begin
SyncBufferToPrefix(cutter);
end;
controlY := controlY + 30;
// Dossier de sortie (calculé automatiquement)
GuiLabel(RectangleCreate(x, controlY, 150, 15), 'Dossier sortie:');
controlY := controlY + 20;
GuiLabel(RectangleCreate(x, controlY, 150, 15), PChar('./' + filePrefix + '/'));
controlY := controlY + 25;
// Exemple de nom selon le mode
GuiLabel(RectangleCreate(x, controlY, 150, 15), 'Exemple:');
controlY := controlY + 20;
// Générer l'exemple selon le mode actuel
if cellDisplayMode then
begin
if versoMode then
exampleText := filePrefix + '_1.png (verso)'
else
exampleText := filePrefix + '_1.png (recto)';
end
else
begin
if versoMode then
exampleText := filePrefix + '_L0C0.png (verso)'
else
exampleText := filePrefix + '_L0C0.png (recto)';
end;
GuiLabel(RectangleCreate(x, controlY, 220, 15), PChar(exampleText));
end;
end;
procedure DrawActionButtons(var cutter: TImageCutter; x, y: Integer);
var
buttonY: Integer;
gridButtonText: string;
begin
buttonY := 500;
with cutter do
begin
// Bouton charger/changer image
if imageLoaded and not showFileList then
begin
if GuiButton(RectangleCreate(x, buttonY, 120, 30), 'Changer Image') <> 0 then
begin
showFileList := True;
WriteLn('Retour à la liste de sélection');
end;
end
else
begin
if GuiButton(RectangleCreate(x, buttonY, 120, 30), 'Choisir Image') <> 0 then
begin
if not showFileList then
begin
showFileList := True;
WriteLn('Affichage de la liste de sélection');
end;
end;
end;
buttonY := buttonY + 40;
// Bouton toggle grille
if grid.visible then
gridButtonText := 'Masquer Grille'
else
gridButtonText := 'Afficher Grille';
if (GuiButton(RectangleCreate(x, buttonY, 120, 30), PChar(gridButtonText)) <> 0) and imageLoaded and not showFileList then
begin
grid.visible := not grid.visible;
WriteLn('Grille visible: ', grid.visible);
end;
buttonY := buttonY + 40;
// Bouton découpage
GuiSetState(STATE_NORMAL);
if not imageLoaded or (grid.rows = 0) or (grid.cols = 0) or showFileList then
GuiSetState(STATE_DISABLED);
if GuiButton(RectangleCreate(x, buttonY, 120, 30), 'Lancer Découpage') <> 0 then
begin
SaveAllCells(cutter);
end;
GuiSetState(STATE_NORMAL);
end;
end;
procedure DrawRightPanel(var cutter: TImageCutter);
var
panelX, panelY: Integer;
currentY: Integer;
modeText, versoText: string;
begin
with cutter do
begin
panelX := screenWidth - rightPanelWidth;
panelY := 0;
// Fond du panneau
DrawRectangle(panelX, panelY, rightPanelWidth, screenHeight, Fade(LIGHTGRAY, 0.9));
DrawRectangleLines(panelX, panelY, rightPanelWidth, screenHeight, DARKGRAY);
currentY := 20;
// Informations de l'image
DrawImageInfo(cutter, panelX + 10, currentY);
currentY := currentY + 100;
// Contrôles de la grille
DrawGridControls(cutter, panelX + 10, currentY);
currentY := currentY + 280; // Plus d'espace pour le nouveau checkbox
// Contrôles des fichiers
DrawFileControls(cutter, panelX + 10, currentY);
currentY := currentY + 170;
// Boutons d'action
DrawActionButtons(cutter, panelX + 10, currentY);
// Aide clavier
currentY := screenHeight - 140;
GuiLabel(RectangleCreate(panelX + 10, currentY, 150, 15), 'RACCOURCIS:');
currentY := currentY + 20;
GuiLabel(RectangleCreate(panelX + 10, currentY, 150, 15), 'G: Toggle grille');
currentY := currentY + 15;
GuiLabel(RectangleCreate(panelX + 10, currentY, 150, 15), 'Flèches: Déplacer');
currentY := currentY + 15;
GuiLabel(RectangleCreate(panelX + 10, currentY, 150, 15), 'M: Mode affichage');
currentY := currentY + 15;
GuiLabel(RectangleCreate(panelX + 10, currentY, 150, 15), 'Double-clic: 1 case');
currentY := currentY + 15;
GuiLabel(RectangleCreate(panelX + 10, currentY, 150, 15), 'Espace: Découper');
// Afficher les modes actuels
if cellDisplayMode then
modeText := 'Affichage: Numéro'
else
modeText := 'Affichage: Coordonnées';
currentY := currentY + 20;
GuiLabel(RectangleCreate(panelX + 10, currentY, 150, 15), PChar(modeText));
if versoMode then
versoText := 'Parcours: Verso'
else
versoText := 'Parcours: Recto';
currentY := currentY + 15;
GuiLabel(RectangleCreate(panelX + 10, currentY, 150, 15), PChar(versoText));
end;
end;
procedure UpdateGUI(var cutter: TImageCutter);
begin
// Cette fonction sera appelée dans la boucle principale
// pour mettre à jour l'état de l'interface
end;
procedure HandleKeyboardInput(var cutter: TImageCutter);
begin
with cutter do
begin
// Toggle grille
if IsKeyPressed(KEY_G) and imageLoaded then
begin
grid.visible := not grid.visible;
WriteLn('Grille visible (clavier): ', grid.visible);
end;
// Commuter le mode d'affichage des cellules
if IsKeyPressed(KEY_M) then
begin
cellDisplayMode := not cellDisplayMode;
if cellDisplayMode then
WriteLn('Mode affichage: Numéro linéaire')
else
WriteLn('Mode affichage: Coordonnées');
end;
// Déplacement de la grille - AUTO REPEAT avec IsKeyDown
if imageLoaded and grid.visible then
begin
if IsKeyDown(KEY_RIGHT) then
begin
grid.offsetX := grid.offsetX + 1;
end;
if IsKeyDown(KEY_LEFT) then
begin
grid.offsetX := grid.offsetX - 1;
end;
if IsKeyDown(KEY_DOWN) then
begin
grid.offsetY := grid.offsetY + 1;
end;
if IsKeyDown(KEY_UP) then
begin
grid.offsetY := grid.offsetY - 1;
end;
// Pas de limitation de déplacement en mode carré fixe (peut dépasser)
if not fixedSquareMode then
begin
// Limiter le déplacement seulement en mode rectangle adaptatif
if grid.offsetX < -(grid.cellWidth * (grid.cols - 1)) then
grid.offsetX := -(grid.cellWidth * (grid.cols - 1));
if grid.offsetX > grid.cellWidth then
grid.offsetX := grid.cellWidth;
if grid.offsetY < -(grid.cellHeight * (grid.rows - 1)) then
grid.offsetY := -(grid.cellHeight * (grid.rows - 1));
if grid.offsetY > grid.cellHeight then
grid.offsetY := grid.cellHeight;
end;
end;
// Lancer le découpage
if IsKeyPressed(KEY_SPACE) and imageLoaded and (grid.rows > 0) and (grid.cols > 0) then
begin
SaveAllCells(cutter);
end;
end;
end;
procedure HandleMouseInput(var cutter: TImageCutter);
var
mousePos: TVector2;
imageArea: TRectangle;
relativeX, relativeY: Integer;
cellX, cellY: Integer;
wheelMove: Single;
currentTime: Double;
timeDiff: Double;
clickedLine: Integer;
deltaX, deltaY: Integer;
minX, maxX, minY, maxY: Integer;
begin
with cutter do
begin
mousePos := GetMousePosition();
// NOUVEAU: Gestion des clics sur la liste de fichiers
if showFileList and IsMouseButtonPressed(MOUSE_BUTTON_LEFT) then
begin
imageArea := RectangleCreate(0, 0, screenWidth - rightPanelWidth, screenHeight);
if CheckCollisionPointRec(mousePos, imageArea) and (imageFiles.count > 0) then
begin
// Calculer quelle ligne est cliquée
if (mousePos.y >= 100) then
begin
clickedLine := Round((mousePos.y - 100) / 30);
if (clickedLine >= 0) and (clickedLine < imageFiles.count) then
begin
WriteLn('Fichier sélectionné: ', ExtractFileName(imageFiles.paths[clickedLine]));
LoadSpecificImage(cutter, imageFiles.paths[clickedLine]);
end;
end;
end;
Exit; // Ne pas traiter les autres clics en mode liste
end;
// Contrôle de la taille du carré avec la molette (en mode carré fixe)
if fixedSquareMode then
begin
wheelMove := GetMouseWheelMove();
if wheelMove <> 0 then
begin
// Molette vers le haut = augmenter, vers le bas = diminuer
squareSize := squareSize + Round(wheelMove * 5); // Pas de 5 pixels
// Limiter entre 10 et 200
if squareSize < 10 then squareSize := 10;
if squareSize > 200 then squareSize := 200;
CalculateGrid(cutter);
WriteLn('Taille carré (molette): ', squareSize, 'px');
end;
end;
if not imageLoaded or showFileList then Exit;
// Définir la zone de l'image (exclut le panneau droit)
imageArea := RectangleCreate(0, 0, screenWidth - rightPanelWidth, screenHeight);
// NOUVEAU: Gestion du glisser-déposer pour déplacer l'image
if CheckCollisionPointRec(mousePos, imageArea) then
begin
if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) then
begin
isDragging := True;
lastMouseX := Round(mousePos.x);
lastMouseY := Round(mousePos.y);
end;
end;
if IsMouseButtonReleased(MOUSE_BUTTON_LEFT) then
begin
isDragging := False;
end;
if isDragging and IsMouseButtonDown(MOUSE_BUTTON_LEFT) then
begin
// Calculer le déplacement
deltaX := Round(mousePos.x) - lastMouseX;
deltaY := Round(mousePos.y) - lastMouseY;
// Appliquer le déplacement
imageOffsetX := imageOffsetX + deltaX;
imageOffsetY := imageOffsetY + deltaY;
// Limiter pour éviter de perdre l'image
minX := -(texture.width - 50); // Garder au moins 50px visibles
maxX := Round(imageArea.width) - 50;
minY := -(texture.height - 50);
maxY := Round(imageArea.height) - 50;
if imageOffsetX < minX then imageOffsetX := minX;
if imageOffsetX > maxX then imageOffsetX := maxX;
if imageOffsetY < minY then imageOffsetY := minY;
if imageOffsetY > maxY then imageOffsetY := maxY;
lastMouseX := Round(mousePos.x);
lastMouseY := Round(mousePos.y);
Exit; // Ne pas traiter la sélection de cellule pendant le drag
end;
// Sélection de cellule seulement si pas en train de glisser et grille visible
if not isDragging and grid.visible and CheckCollisionPointRec(mousePos, imageArea) and IsMouseButtonPressed(MOUSE_BUTTON_LEFT) then
begin
currentTime := GetTime();
// Calculer la position relative dans l'image (échelle 1:1)
relativeX := Round(mousePos.x) - imageOffsetX - grid.offsetX;
relativeY := Round(mousePos.y) - imageOffsetY - grid.offsetY;
// Calculer quelle cellule est sélectionnée
if (grid.cellWidth > 0) and (grid.cellHeight > 0) then
begin
cellX := relativeX div grid.cellWidth;
cellY := relativeY div grid.cellHeight;
if (cellX >= 0) and (cellX < grid.cols) and (cellY >= 0) and (cellY < grid.rows) then
begin
selectedCellX := cellX;
selectedCellY := cellY;
// Gestion du double-clic (300ms)
if lastClickTime > 0 then
begin
timeDiff := (currentTime - lastClickTime) * 1000; // Convertir en millisecondes
if timeDiff <= 300 then
begin
// Double-clic détecté ! Sauvegarder la case
WriteLn('Double-clic détecté - Sauvegarde case: ', cellX, ',', cellY);
SaveSingleCell(cutter, cellX, cellY);
lastClickTime := 0; // Reset pour éviter les triple-clics
end
else
begin
// Trop tard, c'est un nouveau premier clic
lastClickTime := currentTime;
end;
end
else
begin
// Premier clic
lastClickTime := currentTime;
end;
if cellDisplayMode then
WriteLn('Case sélectionnée: ', (selectedCellY * grid.cols) + selectedCellX + 1)
else
WriteLn('Cellule sélectionnée: ', selectedCellX, ',', selectedCellY);
end;
end;
end;
end;
end;
end.