@@ -20,6 +20,9 @@ document.addEventListener("DOMContentLoaded", () => {
2020 const closeHelpButton = document . getElementById ( "close-help" ) ;
2121 const slider = document . getElementById ( "slider" ) ;
2222 const sliderPopup = document . getElementById ( "slider-popup" ) ;
23+ const sliderValueLabel = document . getElementById ( "slider-value" ) ;
24+
25+ let activePattern = null ;
2326
2427 const maxRows = Math . floor ( editor . getBoundingClientRect ( ) . height / 16 ) ; // Assuming 16px line height
2528 const maxCols = Math . floor ( editor . getBoundingClientRect ( ) . width / 10 ) ; // Assuming 10px character width
@@ -122,14 +125,151 @@ document.addEventListener("DOMContentLoaded", () => {
122125 min = Math . min ( val1 , val2 ) ;
123126 max = Math . max ( val1 , val2 ) ;
124127 const numericValue = convertHexOrFloat ( value ) ;
125- console . log ( `Minimum Value (min): ${ min } ` ) ;
126- console . log ( `Maximum Value (max): ${ max } ` ) ;
127- console . log ( "Numeric Value:" , numericValue ) ;
128+ // console.log(`Minimum Value (min): ${min}`);
129+ // console.log(`Maximum Value (max): ${max}`);
130+ // console.log("Numeric Value:", numericValue);
128131 }
129132 }
130133 }
131134 }
132135 } ) ;
136+ editor . addEventListener ( "click" , ( event ) => {
137+ const patternInfo = getPatternAtPosition ( event ) ;
138+ if ( patternInfo ) {
139+ activePattern = patternInfo ;
140+ const { min, max, numericValue, event : evt } = patternInfo ;
141+
142+ slider . min = min ;
143+ slider . max = max ;
144+ // For float values, we need to set a step
145+ if ( max === 1 && min === 0 ) {
146+ slider . step = 0.1 ;
147+ } else if (
148+ Number . isFinite ( min ) &&
149+ Number . isFinite ( max ) &&
150+ ( min % 1 !== 0 || max % 1 !== 0 )
151+ ) {
152+ slider . step = ( max - min ) / 10 ;
153+ } else {
154+ slider . step = 1 ;
155+ }
156+ slider . value = numericValue ;
157+ sliderValueLabel . textContent = numericValue ;
158+
159+ sliderPopup . style . display = "block" ;
160+ sliderPopup . style . left = `${ event . pageX + 10 } px` ;
161+ sliderPopup . style . top = `${ event . pageY } px` ;
162+ } else {
163+ sliderPopup . style . display = "none" ;
164+ activePattern = null ;
165+ }
166+ } ) ;
167+
168+ slider . addEventListener ( "input" , ( ) => {
169+ if ( activePattern ) {
170+ const { originalValue, start, end, lineIndex } = activePattern ;
171+ let newValue = slider . value ;
172+
173+ // Preserve original format (e.g. float with specific precision)
174+ if ( originalValue . includes ( "." ) ) {
175+ const precision = ( originalValue . split ( "." ) [ 1 ] || "" ) . length ;
176+ newValue = parseFloat ( newValue ) . toFixed ( precision ) ;
177+ }
178+
179+ sliderValueLabel . textContent = newValue ;
180+
181+ const lines = editor . value . split ( "\n" ) ;
182+ const line = lines [ lineIndex ] ;
183+
184+ const updatedLine =
185+ line . substring ( 0 , start ) + newValue + line . substring ( end ) ;
186+ lines [ lineIndex ] = updatedLine ;
187+
188+ // To avoid losing cursor position, we can try to restore it.
189+ const { selectionStart, selectionEnd } = editor ;
190+ editor . value = lines . join ( "\n" ) ;
191+
192+ // After updating the value, we need to update the end position for the active pattern
193+ activePattern . end = start + String ( newValue ) . length ;
194+
195+ // Restore cursor position
196+ editor . setSelectionRange ( selectionStart , selectionEnd ) ;
197+
198+ if ( renderer . run ) {
199+ renderer . run ( ) ;
200+ }
201+ }
202+ } ) ;
203+
204+ function getPatternAtPosition ( event ) {
205+ const textarea = editor ;
206+ const rect = textarea . getBoundingClientRect ( ) ;
207+ const mouseX = event . clientX - rect . left ;
208+ const mouseY = event . clientY - rect . top ;
209+
210+ const adjustedMouseY = mouseY + textarea . scrollTop ;
211+ const lineHeight = 20 ;
212+ const targetRow = Math . floor ( adjustedMouseY / lineHeight ) ;
213+
214+ const lines = textarea . value . split ( "\n" ) ;
215+ if ( targetRow >= lines . length ) return null ;
216+
217+ const line = lines [ targetRow ] ;
218+ const charWidth = ctx . measureText ( "M" ) . width ;
219+ let charIndex = Math . floor ( mouseX / charWidth ) ;
220+ charIndex = Math . max ( 0 , Math . min ( charIndex , line . length - 1 ) ) ;
221+
222+ let start = - 1 ,
223+ end = - 1 ;
224+
225+ // Find word boundaries
226+ for ( let i = charIndex ; i >= 0 ; i -- ) {
227+ if ( / \s / . test ( line [ i ] ) ) break ;
228+ start = i ;
229+ }
230+ for ( let i = charIndex ; i < line . length ; i ++ ) {
231+ if ( / \s / . test ( line [ i ] ) ) break ;
232+ end = i + 1 ;
233+ }
234+
235+ if ( start === - 1 || end === - 1 ) return null ;
236+
237+ const word = line . substring ( start , end ) ;
238+ const regex =
239+ / ( [ - + ] ? (?: 0 x [ a - f A - F 0 - 9 ] + | # ? [ a - f A - F 0 - 9 ] + | \d * \. ? \d + ) ) \s * \/ \* \[ ( .* ?) \] \* \/ / ;
240+ const match = line . match ( regex ) ;
241+
242+ if ( match ) {
243+ const matchedValue = match [ 1 ] ;
244+ const rangeString = match [ 2 ] ;
245+ const valueIndex = line . indexOf ( matchedValue ) ;
246+ const valueEnd = valueIndex + matchedValue . length ;
247+
248+ const rangeMatch = rangeString . match (
249+ / ^ \s * ( [ - + ] ? \d * \. ? \d + ) \s * \. \. \s * ( [ - + ] ? \d * \. ? \d + ) \s * $ /
250+ ) ;
251+
252+ if ( rangeMatch ) {
253+ const min = convertHexOrFloat ( rangeMatch [ 1 ] ) ;
254+ const max = convertHexOrFloat ( rangeMatch [ 2 ] ) ;
255+ const numericValue = convertHexOrFloat ( matchedValue ) ;
256+
257+ return {
258+ originalValue : matchedValue ,
259+ numericValue,
260+ min,
261+ max,
262+ start : valueIndex ,
263+ end : valueEnd ,
264+ lineIndex : targetRow ,
265+ event : event ,
266+ } ;
267+ }
268+ }
269+
270+ return null ;
271+ }
272+
133273 function convertHexOrFloat ( valString ) {
134274 if ( valString . startsWith ( "0x" ) ) {
135275 // Handle 0x hex format (e.g., 0xFF)
@@ -144,8 +284,18 @@ document.addEventListener("DOMContentLoaded", () => {
144284 }
145285 }
146286
147- editor . addEventListener ( "mouseleave" , ( ) => {
148- sliderPopup . style . display = "none" ; // Hide the slider when mouse leaves
287+ editor . addEventListener ( "mouseleave" , ( e ) => {
288+ // If the mouse is not moving to the slider popup, hide it.
289+ if ( ! sliderPopup . contains ( e . relatedTarget ) ) {
290+ sliderPopup . style . display = "none" ;
291+ }
292+ } ) ;
293+
294+ sliderPopup . addEventListener ( "mouseleave" , ( e ) => {
295+ // If the mouse is not moving back into the editor, hide the popup.
296+ if ( e . relatedTarget !== editor ) {
297+ sliderPopup . style . display = "none" ;
298+ }
149299 } ) ;
150300
151301 // --- State ---
0 commit comments