refactor: reglages de calibration au-dessus de la photo + boutons de taille fonctionnels
This commit is contained in:
@@ -110,6 +110,9 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
||||
bool _isCalibrating = true;
|
||||
bool _isAtBottom = false;
|
||||
|
||||
// Affichage du réglage manuel de l'espacement des anneaux.
|
||||
bool _showSpacing = false;
|
||||
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
final GlobalKey _imageKey = GlobalKey();
|
||||
|
||||
@@ -143,7 +146,12 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
||||
/// La cible du mode Plotting est désormais un élément fixe (aucun zoom à
|
||||
/// réinitialiser) : on se contente donc de rebasculer l'état.
|
||||
void _enterCalibration() {
|
||||
setState(() => _isCalibrating = true);
|
||||
setState(() {
|
||||
_isCalibrating = true;
|
||||
// La calibration est reconstruite à neuf (espacement manuel désactivé) :
|
||||
// on aligne l'état du panneau pour ne pas afficher un mode inactif.
|
||||
_showSpacing = false;
|
||||
});
|
||||
}
|
||||
|
||||
/// Ouvre l'éditeur d'impacts (plein écran) en PARTAGEANT le provider courant.
|
||||
@@ -182,6 +190,113 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
||||
return widget.originalImagePath ?? provider.imagePath!;
|
||||
}
|
||||
|
||||
/// Panneau de réglages de la calibration (taille + espacement).
|
||||
///
|
||||
/// Rendu AU-DESSUS de l'image (et non plus en surimpression) pour ne pas
|
||||
/// masquer la cible. Les valeurs affichées viennent du provider ; les
|
||||
/// modifications sont poussées dans l'état de [TargetCalibration] via sa clé.
|
||||
Widget _buildCalibrationSettings(AnalysisProvider provider) {
|
||||
final radius = provider.targetRadius.clamp(
|
||||
TargetCalibrationState.minRadius,
|
||||
TargetCalibrationState.maxRadius,
|
||||
);
|
||||
final spacing =
|
||||
(provider.targetRadius > 0
|
||||
? provider.targetInnerRadius / provider.targetRadius
|
||||
: 0.1)
|
||||
.clamp(
|
||||
TargetCalibrationState.minSpacing,
|
||||
TargetCalibrationState.maxSpacing,
|
||||
);
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(12, 0, 12, 4),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 36,
|
||||
child: Row(
|
||||
children: [
|
||||
const Text(
|
||||
'Taille',
|
||||
style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
const Icon(Icons.zoom_out, size: 16),
|
||||
Expanded(
|
||||
child: Slider(
|
||||
value: radius,
|
||||
min: TargetCalibrationState.minRadius,
|
||||
max: TargetCalibrationState.maxRadius,
|
||||
activeColor: AppTheme.primaryColor,
|
||||
onChanged: (value) =>
|
||||
_calibrationKey.currentState?.setRadius(value),
|
||||
),
|
||||
),
|
||||
const Icon(Icons.zoom_in, size: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 32,
|
||||
child: Row(
|
||||
children: [
|
||||
const Expanded(
|
||||
child: Text(
|
||||
'Options d\'espacement avancées',
|
||||
style: TextStyle(fontSize: 11, fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
Switch(
|
||||
value: _showSpacing,
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
onChanged: (value) {
|
||||
setState(() => _showSpacing = value);
|
||||
_calibrationKey.currentState?.setSpacingMode(value);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (_showSpacing)
|
||||
SizedBox(
|
||||
height: 36,
|
||||
child: Row(
|
||||
children: [
|
||||
const Text(
|
||||
'Espacement',
|
||||
style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
const Icon(Icons.compress, size: 16),
|
||||
Expanded(
|
||||
child: Slider(
|
||||
value: spacing,
|
||||
min: TargetCalibrationState.minSpacing,
|
||||
max: TargetCalibrationState.maxSpacing,
|
||||
activeColor: Colors.orange,
|
||||
onChanged: (value) =>
|
||||
_calibrationKey.currentState?.setSpacingRatio(value),
|
||||
),
|
||||
),
|
||||
const Icon(Icons.expand, size: 16),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh, size: 20),
|
||||
tooltip: 'Réinitialiser l\'espacement',
|
||||
constraints: const BoxConstraints(),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
onPressed: () =>
|
||||
_calibrationKey.currentState?.resetSpacing(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final provider = context.watch<AnalysisProvider>();
|
||||
@@ -230,21 +345,17 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
|
||||
controller: _scrollController,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(AppConstants.defaultPadding),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (provider.state == AnalysisState.loading)
|
||||
const Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
],
|
||||
// Plus de bloc vide au-dessus de l'image : l'indicateur n'occupe
|
||||
// de la place que pendant le chargement.
|
||||
if (provider.state == AnalysisState.loading)
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
),
|
||||
|
||||
// Réglages de calibration : au-dessus de la photo pour ne rien
|
||||
// masquer de la cible.
|
||||
if (_isCalibrating) _buildCalibrationSettings(provider),
|
||||
|
||||
AspectRatio(
|
||||
aspectRatio: provider.imageAspectRatio,
|
||||
|
||||
Reference in New Issue
Block a user