File size: 7,862 Bytes
6bda4a6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { useEffect, useRef } from 'react';
import { Pane } from 'tweakpane';
import { GLYPH_CONFIG } from '../utils/constants.js';
import { useDebugUMAPStore } from '../store';

/**
 * Hook pour gérer l'interface Tweakpane avec Zustand
 */
export function useTweakpane({ onResetZoom }) {
  const configs = useDebugUMAPStore((state) => state.configs);
  const currentConfigIndex = useDebugUMAPStore((state) => state.currentConfigIndex);
  const setCurrentConfigIndex = useDebugUMAPStore((state) => state.setCurrentConfigIndex);
  const getTotalConfigs = useDebugUMAPStore((state) => state.getTotalConfigs);
  const useCategoryColors = useDebugUMAPStore((state) => state.useCategoryColors);
  const setUseCategoryColors = useDebugUMAPStore((state) => state.setUseCategoryColors);
  const baseGlyphSize = useDebugUMAPStore((state) => state.baseGlyphSize);
  const setBaseGlyphSize = useDebugUMAPStore((state) => state.setBaseGlyphSize);
  const darkMode = useDebugUMAPStore((state) => state.darkMode);
  const setDarkMode = useDebugUMAPStore((state) => state.setDarkMode);
  const resetToDefaults = useDebugUMAPStore((state) => state.resetToDefaults);
  const paneRef = useRef(null);
  const paneInstanceRef = useRef(null);
  const bindingsRef = useRef({});

  // Gestion de la navigation au clavier
  useEffect(() => {
    const handleKeyDown = (event) => {
      if (configs.length === 0) return;
      
      if (event.key === 'ArrowLeft') {
        event.preventDefault();
        const newIndex = currentConfigIndex > 0 
          ? currentConfigIndex - 1 
          : configs.length - 1; // Boucler à la fin
        setCurrentConfigIndex(newIndex);
      } else if (event.key === 'ArrowRight') {
        event.preventDefault();
        const newIndex = currentConfigIndex < configs.length - 1 
          ? currentConfigIndex + 1 
          : 0; // Boucler au début
        setCurrentConfigIndex(newIndex);
      }
    };

    // Ajouter l'écouteur d'événements
    document.addEventListener('keydown', handleKeyDown);
    
    return () => {
      document.removeEventListener('keydown', handleKeyDown);
    };
  }, [configs.length, currentConfigIndex]);

  // Initialiser Tweakpane
  useEffect(() => {
    console.log('Tweakpane useEffect déclenché:', {
      configsLength: configs.length,
      hasPaneInstance: !!paneInstanceRef.current,
      shouldInitialize: configs.length > 0 && !paneInstanceRef.current
    });
    
    if (configs.length === 0 || paneInstanceRef.current) return;
    
    // Vérifier que les valeurs sont valides
    console.log('Valeurs Tweakpane:', {
      currentConfigIndex,
      useCategoryColors,
      baseGlyphSize,
      darkMode,
      types: {
        currentConfigIndex: typeof currentConfigIndex,
        useCategoryColors: typeof useCategoryColors,
        baseGlyphSize: typeof baseGlyphSize,
        darkMode: typeof darkMode
      }
    });
    
    if (typeof currentConfigIndex !== 'number' || 
        typeof useCategoryColors !== 'boolean' || 
        typeof baseGlyphSize !== 'number' || 
        typeof darkMode !== 'boolean') {
      console.warn('Valeurs invalides pour Tweakpane, attente...', {
        currentConfigIndex,
        useCategoryColors,
        baseGlyphSize,
        darkMode
      });
      return;
    }

    // Vérifier que le conteneur existe
    console.log('Conteneur Tweakpane:', paneRef.current);
    if (!paneRef.current) {
      console.warn('Conteneur Tweakpane non trouvé');
      return;
    }

    const pane = new Pane({
      container: paneRef.current,
      title: 'UMAP Debug',
      expanded: true,
    });

    // Créer les bindings un par un pour éviter les erreurs
    try {
      // Slider de configuration
      const maxConfigIndex = Math.max(0, configs.length - 1);
      const validConfigIndex = Math.min(Math.max(0, currentConfigIndex), maxConfigIndex);
      
      bindingsRef.current.config = pane.addBinding(
        { configuration: validConfigIndex }, 
        'configuration', 
        {
          min: 0,
          max: maxConfigIndex,
          step: 1,
          label: 'Configuration (← →)',
        }
      ).on('change', (ev) => {
        setCurrentConfigIndex(ev.value);
      });

      // Toggle pour les couleurs
      bindingsRef.current.useCategoryColors = pane.addBinding(
        { useCategoryColors }, 
        'useCategoryColors', 
        {
          label: 'Category Colors',
        }
      ).on('change', (ev) => {
        setUseCategoryColors(ev.value);
      });

      // Slider pour la taille des glyphes
      const validGlyphSize = Math.min(Math.max(GLYPH_CONFIG.minSize, baseGlyphSize), GLYPH_CONFIG.maxSize);
      
      bindingsRef.current.baseGlyphSize = pane.addBinding(
        { baseGlyphSize: validGlyphSize }, 
        'baseGlyphSize', 
        {
          min: GLYPH_CONFIG.minSize,
          max: GLYPH_CONFIG.maxSize,
          step: GLYPH_CONFIG.stepSize,
          label: 'Glyph Size',
        }
      ).on('change', (ev) => {
        setBaseGlyphSize(ev.value);
      });

      // Toggle pour le dark mode
      bindingsRef.current.darkMode = pane.addBinding(
        { darkMode }, 
        'darkMode', 
        {
          label: 'Dark Mode',
        }
      ).on('change', (ev) => {
        setDarkMode(ev.value);
      });

      // Bouton pour reset le zoom
      pane.addButton({
        title: 'Reset Zoom',
      }).on('click', onResetZoom);

      paneInstanceRef.current = pane;
      console.log('Tweakpane initialisé avec succès!');
    } catch (error) {
      console.error('Erreur lors de l\'initialisation de Tweakpane:', error);
      console.error('Détails de l\'erreur:', {
        configsLength: configs.length,
        currentConfigIndex,
        useCategoryColors,
        baseGlyphSize,
        darkMode
      });
    }

    return () => {
      if (paneInstanceRef.current) {
        paneInstanceRef.current.dispose();
        paneInstanceRef.current = null;
        bindingsRef.current = {};
      }
    };
  }, [configs.length]);

  // Mettre à jour les valeurs des contrôles (seulement si nécessaire)
  useEffect(() => {
    if (!paneInstanceRef.current) return;
    
    // Mettre à jour le slider de configuration seulement si la valeur a changé
    if (bindingsRef.current.config && bindingsRef.current.config.value !== currentConfigIndex) {
      try {
        bindingsRef.current.config.value = currentConfigIndex;
      } catch (error) {
        console.warn('Erreur lors de la mise à jour du slider de configuration:', error);
      }
    }
  }, [currentConfigIndex]);

  useEffect(() => {
    if (!paneInstanceRef.current) return;
    
    // Mettre à jour les autres contrôles seulement si les valeurs ont changé
    if (bindingsRef.current.useCategoryColors && bindingsRef.current.useCategoryColors.value !== useCategoryColors) {
      try {
        bindingsRef.current.useCategoryColors.value = useCategoryColors;
      } catch (error) {
        console.warn('Erreur lors de la mise à jour des couleurs:', error);
      }
    }
  }, [useCategoryColors]);

  useEffect(() => {
    if (!paneInstanceRef.current) return;
    
    if (bindingsRef.current.baseGlyphSize && bindingsRef.current.baseGlyphSize.value !== baseGlyphSize) {
      try {
        bindingsRef.current.baseGlyphSize.value = baseGlyphSize;
      } catch (error) {
        console.warn('Erreur lors de la mise à jour de la taille:', error);
      }
    }
  }, [baseGlyphSize]);

  useEffect(() => {
    if (!paneInstanceRef.current) return;
    
    if (bindingsRef.current.darkMode && bindingsRef.current.darkMode.value !== darkMode) {
      try {
        bindingsRef.current.darkMode.value = darkMode;
      } catch (error) {
        console.warn('Erreur lors de la mise à jour du dark mode:', error);
      }
    }
  }, [darkMode]);

  return { paneRef, paneInstanceRef };
}