# Pencere Cascade Yerleşimi Planı

> Tarih: 2026-08-03 · Değerlendirme + implementasyon planı (henüz kod değişikliği yapılmadı)

## 1. Sorun

imajViewer'a yeni bir resim açıldığında pencere **hep aynı koordinat ve boyutta** açılıyor (önceki pencerenin üstüne biniyor). İstenen davranış:

- Yeni pencere, önceki pencerenin **x + width** kadar sağına açılsın (yan yana)
- Ekrandan **taşacaksa** alt satıra, satır başından (x baştan) açılsın

Bu, Windows'un klasik "cascade windows" davranışının basit hali.

## 2. Mevcut Durum Analizi

### Pencere açılış akışı (`lib/main.dart`)
```
main(args)
  → WindowPersistence.restore()      // window.json'dan son konum/boyut
  → windowOptions = WindowOptions(size: saved ?? 1280x800)
  → waitUntilReadyToShow:
      saved varsa  → setPosition(saved.position) + setSize(saved.size)
      saved yoksa  → center()
  → runApp(ImajViewerApp(initialFiles: args))
```

### Konum kaydetme akışı (`lib/screens/viewer_screen.dart` + `lib/services/window_persistence.dart`)
- `_startPolling()`: 2 saniyede bir `windowManager.getBounds()` → `WindowPersistence.saveSync()` → `~/.config/imajviewer/window.json` (Linux) / `%APPDATA%/imajviewer/window.json` (Windows)
- `onWindowEvent` (move/resize/close) → debounce'lu `_doSave()`

### Sorunun kökü
- Her yeni pencere `window.json`'daki **son kaydedilen** konumu okuyor → aynı yere açılıyor
- Cascade mantığı yok; ekran genişliği bilgisi hiç sorgulanmıyor

## 3. Teknik Araştırma (doğrulandı)

### window_manager 0.4.3 (mevcut bağımlılık)
- `setPosition`, `setSize`, `getBounds`, `getPosition`, `getSize`, `center()` → var
- **Ekran/display API'si → YOK** (getScreen/getPrimaryDisplay yok)

### window_manager 0.5.2 (güncel)
- Ekran API'si yine yok — `screen_retriever`'ı bağımlılık olarak içeriyor ama expose etmiyor

### screen_retriever 0.2.2 (pub.dev, window_manager'ın zaten bağımlısı)
- `ScreenRetriever.instance.getPrimaryDisplay()` → `Display`
- `getAllDisplays()` → `List<Display>`
- `Display` alanları:
  - `size` (ekran tam boyutu, logical px)
  - `visiblePosition` (Offset — çalışma alanı başlangıcı)
  - `visibleSize` (Size — görev çubuğu hariç çalışma alanı)
  - `scaleFactor`
- Linux (X11) + Windows desteği var

**Karar: `screen_retriever` doğrudan bağımlılık olarak eklenir** (window_manager sürümü değişmez).

## 4. Önerilen Algoritma

`main.dart`'ta, `windowOptions` oluşturulmadan önce:

```
1. saved = WindowPersistence.restore()
2. display = await ScreenRetriever.instance.getPrimaryDisplay()
   workArea = display.visiblePosition + display.visibleSize  (yoksa display.size)
3. Eğer saved != null:
     newX = saved.x + saved.width        // önceki pencerenin sağına
     newY = saved.y

     // Yatay taşma → alt satıra, satır başına
     if (newX + pencereGenişliği > workArea.right):
         newX = workArea.left
         newY = saved.y + saved.height

     // Dikey taşma da varsa → en başa sar (0,0)
     if (newY + pencereYüksekliği > workArea.bottom):
         newX = workArea.left
         newY = workArea.top

     position = Offset(newX, newY)
4. saved yoksa → center() (mevcut davranış)
```

### Örnek
- Ekran 1920×1080, pencere 1280×800, önceki pencere (100, 50)
- 1. yeni: (1380, 50) — yan yana ✓
- 2. yeni: (100+1280*2 = hesaplanır) → 1380+1280=2660 > 1920 → (0, 850) — alt satır başı ✓

> Not: `saved` her 2 saniyede bir güncellendiği için "önceki pencere" = en son kaydedilmiş konum. Bu, en son açılan pencerenin konumu olur — istenen davranışla uyumlu.

## 5. Yapılacaklar (sıralı)

1. [ ] `pubspec.yaml` → `screen_retriever: ^0.2.2` ekle, `flutter pub get`
2. [ ] `lib/main.dart` → cascade hesabı ekle (yeni bir servis fonksiyonuna taşınabilir)
3. [ ] `lib/services/window_persistence.dart` → `restore()` dışında, cascade hesabı için yardımcı fonksiyon:
   - `static Future<Offset?> cascadePosition({required Size windowSize})` (opsiyonel, temizlik için)
4. [ ] Ekran boyutu alınamazsa (hata / çoklu monitör) → mevcut davranışa düş (saved veya center)
5. [ ] Test: ardışık 3-4 resim aç → yan yana dizilim + taşınca alt satır

## 6. Riskler / Açık Sorular

- **Çoklu monitör:** `getPrimaryDisplay` birincil ekranı verir. İmleç hangi ekrandaysa oraya açılsın mı? (başlangıç: primary)
- **Pencere kapatılıp yenisi açılırsa:** `window.json` son kapanan pencerenin konumunu tutar; yeni pencere onun yanına açılır — boşluk oluşabilir, kabul edilebilir
- **Tam ekran / maximize durumu:** saved boyut maximize ise cascade hesabı yine de eski boyutla yapılır; `window.json` sadece normal durumda yazıldığı için risk düşük
- **Pencere ekrandan tamamen dışarıdaysa:** `restore()` zaten `x < -1000 || y < -1000` guard'ı var (window_persistence.dart:44) — yine de sağlamlaştırılabilir

## 7. Kabul Kriterleri

- [ ] Ardışık 2 pencere: ikincisi birincinin hemen sağında
- [ ] Yatay taşma: yeni pencere alt satıra, satır başından başlar
- [ ] İlk açılışta (kayıt yok) pencere yine ortalanır
- [ ] Pencere boyutu/konumu kaydetme davranışı bozulmaz
- [ ] Linux ve Windows'ta çalışır (screen_retriever her ikisini destekliyor)
