66 -# test 440 Round Gauge
77 -# test 441 Arc Meter
88 -# test 442 Rotary Menu Dial (Keyboard Input)
9- -# test 443 Music Visualizer Dial
109 -# test 444 analog Clock Demo
1110 -# test 445 volume Knob Demo (Keyboard Input)
12- @todo GC9A01 music visualize
1311*/
1412
1513// Section :: libraries
@@ -53,13 +51,11 @@ void drawPointerHelper(int16_t val, uint8_t x, uint8_t y, uint8_t r, uint16_t co
5351void drawGaugeMarkers (uint8_t centerX, uint8_t centerY, uint8_t radius, int startAngle, int endAngle, float scaleFactor, uint16_t color);
5452void drawPointer (int16_t &val, int16_t &oldVal , uint8_t x, uint8_t y, uint8_t r, uint16_t color, uint16_t bcolor);
5553// === Demo 3 ===
56- void rotaryMenuDemo (void ) ; // demo 3
57- int getchar_timeout (int timeout_ms); // demo 3
54+ void rotaryMenuDemo (void );
55+ int getchar_timeout (int timeout_ms);
5856// === Demo 4 ===
59- void musicVisualizerDialDemo (uint16_t countLimit = 50 );
60- // === Demo 5 ===
6157void analogClockDemo (uint16_t countLimit = 50 );
62- // === Demo 6 ===
58+ // === Demo 5 ===
6359void volumeKnobDemo (void );
6460
6561// Section :: MAIN loop
@@ -75,25 +71,24 @@ int main()
7571 if (std::cin.fail ()) {
7672 std::cin.clear (); // Clear error flag
7773 std::cin.ignore (std::numeric_limits<std::streamsize>::max (), ' \n ' ); // Discard invalid input
78- std::cout << " Invalid input. Please enter a number between 1 and 4 .\n\n " ;
74+ std::cout << " Invalid input. Please enter a number between 1 and 5 .\n\n " ;
7975 continue ;
8076 }
8177 switch (choice) {
8278 case 1 : gaugeDemo (100 ); break ;
8379 case 2 : arcGauge (100 ); break ;
8480 case 3 : rotaryMenuDemo () ; break ;
85- case 4 : musicVisualizerDialDemo (50 ); break ;
86- case 5 : analogClockDemo (50 ); break ;
87- case 6 : volumeKnobDemo (); break ;
88- case 7 :
81+ case 4 : analogClockDemo (50 ); break ;
82+ case 5 : volumeKnobDemo (); break ;
83+ case 6 :
8984 std::cout << " Exiting menu\n " ;
9085 break ;
9186 default :
9287 std::cout << " Invalid choice. Please try again.\n " ;
9388 break ;
9489 }
9590 std::cout << std::endl;
96- } while (choice != 7 );
91+ } while (choice != 6 );
9792
9893 EndTests ();
9994 return 0 ;
@@ -135,10 +130,9 @@ void displayMenu() {
135130 std::cout << " 1. Round Gauge Demo\n " ;
136131 std::cout << " 2. Arc Gauge Demo\n " ;
137132 std::cout << " 3. Rotary Menu Demo\n " ;
138- std::cout << " 4. Music Visualizer Dial Demo\n " ;
139- std::cout << " 5. Analog Clock Demo\n " ;
140- std::cout << " 6. Volume Knob Demo\n " ;
141- std::cout << " 7. Quit\n " ;
133+ std::cout << " 4. Analog Clock Demo\n " ;
134+ std::cout << " 5. Volume Knob Demo\n " ;
135+ std::cout << " 6. Quit\n " ;
142136 std::cout << " Enter your choice: " ;
143137}
144138
@@ -163,8 +157,8 @@ void signal_callback_handler(int signum)
163157void gaugeDemo (uint16_t countLimit) // Demo 1
164158{
165159 std::cout << " Gauge Demo 1 ends at seconds: " << countLimit << std::endl;
166- int16_t currentValue = 100 ;
167- int16_t oldValue = 100 ;
160+ int16_t currentValue = 120 ;
161+ int16_t oldValue = 120 ;
168162 myTFT.setFont (font_mega);
169163 char buffer[10 ];
170164 // Draw Gauge
@@ -213,7 +207,7 @@ void arcGauge(uint16_t countLimit) // demo 2
213207 // Draw Gauge
214208 uint16_t count = 1 ;
215209 uint16_t x = 120 ;
216- uint16_t y = 120 ;
210+ uint16_t y =120 ;
217211 uint16_t radius = 90 ;
218212 const int16_t minValue = 1 ;
219213 const int16_t maxValue = 255 ;
@@ -250,79 +244,6 @@ void arcGauge(uint16_t countLimit) // demo 2
250244 std::cout << " Arc Gauge Demo Over" << std::endl;
251245}
252246
253- void rotaryMenuDemo ()
254- {
255- std::cout << " Demo 3 Start: press a or d to move pointer , q to quit" << std::endl;
256- myTFT.setFont (font_default);
257- constexpr uint8_t centerX = 120 ;
258- constexpr uint8_t centerY = 120 ;
259- constexpr uint8_t radius = 60 ;
260- constexpr uint8_t itemCount = 6 ;
261- constexpr uint8_t nodeRadius = 16 ;
262- struct MenuItem { const char * label; };
263- MenuItem items[itemCount] = {
264- {" Volts" }, {" Power" }, {" Amps" },
265- {" Watts" }, {" System" }, {" Diode" }
266- };
267-
268- auto drawItem = [&](uint8_t index, bool selected) {
269- float angle = 2 .0f * std::numbers::pi * index / itemCount;
270- int x = centerX + static_cast <int >(radius * std::cos (angle));
271- int y = centerY + static_cast <int >(radius * std::sin (angle));
272-
273- uint16_t color = selected ? myTFT.RDLC_RED : myTFT.RDLC_WHITE ;
274- myTFT.fillCircle (x, y, nodeRadius, color);
275- myTFT.setTextColor (myTFT.RDLC_BLACK , color);
276-
277- char c[2 ] = { items[index].label [0 ], ' \0 ' };
278- myTFT.writeCharString (x - 3 , y - 4 , c);
279- };
280-
281- auto drawPointer = [&](uint8_t index, uint16_t color) {
282- float angle = 2 .0f * std::numbers::pi * index / itemCount;
283- constexpr uint8_t pointerLength = radius - 10 ;
284- int x1 = centerX + static_cast <int >(pointerLength * std::cos (angle));
285- int y1 = centerY + static_cast <int >(pointerLength * std::sin (angle));
286- myTFT.drawLine (centerX, centerY, x1, y1, color);
287- myTFT.fillCircle (centerX, centerY, 2 , myTFT.RDLC_GREEN );
288- };
289- myTFT.fillScreen (myTFT.RDLC_BLACK );
290- myTFT.setTextColor (myTFT.RDLC_WHITE , myTFT.RDLC_BLACK );
291- myTFT.drawArc (centerX, centerY, radius+40 , 10 ,135 .0f , 45 .0f , myTFT.RDLC_GREEN );
292- for (uint8_t i = 0 ; i < itemCount; ++i){
293- drawItem (i, i == 0 );}
294- uint8_t selected = 0 ;
295- int8_t oldSelected = -1 ;
296- drawPointer (selected, myTFT.RDLC_YELLOW );
297- while (true ) {
298- int ch = getchar_timeout (1000 );
299- if (ch == ' q' || ch == ' Q' ) break ;
300- oldSelected = selected;
301- if (ch == ' a' || ch == ' A' )
302- selected = (selected + itemCount - 1 ) % itemCount;
303- if (ch == ' d' || ch == ' D' )
304- selected = (selected + 1 ) % itemCount;
305- if (selected != oldSelected) {
306- drawPointer (oldSelected, myTFT.RDLC_BLACK ); // erase
307- drawItem (oldSelected, false );
308- drawItem (selected, true );
309- drawPointer (selected, myTFT.RDLC_YELLOW ); // draw new
310- // label below
311- myTFT.setFont (font_mega);
312- myTFT.setTextColor (myTFT.RDLC_RED , myTFT.RDLC_YELLOW );
313- myTFT.fillRect (centerX - 30 , centerY + radius + 35 , 80 , 16 , myTFT.RDLC_BLACK );
314- char buf[20 ];
315- std::strncpy (buf, items[selected].label , sizeof (buf));
316- buf[sizeof (buf) - 1 ] = ' \0 ' ;
317- myTFT.writeCharString (centerX-50 , centerY + radius + 35 , buf);
318- myTFT.setFont (font_default);
319- }
320- }
321- myTFT.fillScreen (myTFT.RDLC_BLACK );
322- std::cout << " Demo 3 Over" << std::endl;
323- }
324-
325-
326247void drawGaugeMarkers (uint8_t centerX, uint8_t centerY, uint8_t radius, int startAngle, int endAngle, float scaleFactor, uint16_t color)
327248{
328249 float angleRad, innerX, innerY, outerX, outerY;
@@ -347,7 +268,7 @@ void drawGaugeMarkers(uint8_t centerX, uint8_t centerY, uint8_t radius, int star
347268
348269void drawPointer (int16_t ¤tValue, int16_t &oldValue, uint8_t x, uint8_t y, uint8_t r, uint16_t colour, uint16_t bcolour)
349270{
350- uint8_t i;
271+ uint16_t i;
351272 // If the current value is increasing
352273 if (currentValue > oldValue)
353274 {
@@ -434,67 +355,90 @@ int getchar_timeout(int timeout_ms) {
434355 return ch;
435356}
436357
437- /* !
438- @brief demo 4 Music visualizer radial dial demo.
439- @param count Duration in seconds to run the animation.
440- @details This creates a circular music visualizer using randomized bar heights and color gradients.
441- A pulsing center circle and a rotating rainbow arc enhance visual rhythm.
442- Includes a simulated BPM counter for additional display dynamics.
443- */
444- void musicVisualizerDialDemo (uint16_t count)
358+ void rotaryMenuDemo ()
445359{
446- std::cout << " Music Visualizer Dial Start : Ends in Seconds : " << count << std::endl;
447- constexpr uint16_t timeDelay = 200 ; // ms
360+ std::cout << " Demo 3 Start: press a or d to move pointer , q to quit " << std::endl;
361+ myTFT. setFont (font_default);
448362 constexpr uint8_t centerX = 120 ;
449363 constexpr uint8_t centerY = 120 ;
450- constexpr uint8_t radiusInner = 20 ;
451- constexpr uint8_t radiusOuter = 100 ;
452- constexpr uint8_t barCount = 32 ;
453- constexpr float angleStep = 2 .0f * std::numbers::pi / barCount;
364+ constexpr uint8_t radius = 60 ;
365+ constexpr uint8_t itemCount = 6 ;
366+ constexpr uint8_t nodeRadius = 16 ;
367+ struct MenuItem { const char * label; };
368+ MenuItem items[itemCount] = {
369+ {" Volts" }, {" Power" }, {" Amps" },
370+ {" Watts" }, {" System" }, {" Diode" }
371+ };
372+ // Lambda to draw each node
373+ auto drawItem = [&](uint8_t index, bool selected) {
374+ float angle = 2 .0f * std::numbers::pi * index / itemCount;
375+ int x = centerX + static_cast <int >(radius * std::cos (angle));
376+ int y = centerY + static_cast <int >(radius * std::sin (angle));
377+ uint16_t color = selected ? myTFT.RDLC_RED : myTFT.RDLC_WHITE ;
378+ myTFT.fillCircle (x, y, nodeRadius, color);
379+ myTFT.setTextColor (myTFT.RDLC_BLACK , color);
380+ char c[2 ] = { items[index].label [0 ], ' \0 ' };
381+ myTFT.writeCharString (x - 3 , y - 4 , c);
382+ };
383+ // Lambda to draw pointer from center to selected node
384+ auto drawPointer = [&](uint8_t index, uint16_t color) {
385+ float angle = 2 .0f * std::numbers::pi * index / itemCount;
386+ constexpr uint8_t pointerLength = radius - 10 ;
387+ int x1 = centerX + static_cast <int >(pointerLength * std::cos (angle));
388+ int y1 = centerY + static_cast <int >(pointerLength * std::sin (angle));
389+ myTFT.drawLine (centerX, centerY, x1, y1, color);
390+ myTFT.fillCircle (centerX, centerY, 2 , myTFT.RDLC_GREEN );
391+ };
454392 myTFT.fillScreen (myTFT.RDLC_BLACK );
455- srand (time (NULL ));
456- uint8_t hueOffset = 0 ;
457-
458- while (count-- > 0 )
459- {
460- // Outer dynamic rainbow arc
461- for (uint8_t i = 0 ; i < barCount; ++i) {
462- float angleStart = i * angleStep * 180 .0f / std::numbers::pi;
463- float angleEnd = angleStart + angleStep * 180 .0f / std::numbers::pi;
464- uint16_t arcColor = rdlib_maths::generateColor ((i + hueOffset) % 128 );
465- myTFT.drawSimpleArc (centerX, centerY, radiusOuter + 18 , angleStart, angleEnd, arcColor);
466- }
467- hueOffset += 3 ;
468- // Audio bars
469- for (uint8_t i = 0 ; i < barCount; ++i) {
470- float angle = i * angleStep - std::numbers::pi / 2 .0f ;
471- uint8_t level = rand () % 128 ;
472- uint16_t color = rdlib_maths::generateColor (level);
473- float magnitude = static_cast <float >(level) / 127 .0f ;
474- uint8_t dynamicOuter = radiusInner + static_cast <uint8_t >((radiusOuter - radiusInner) * magnitude);
475- int16_t x0 = centerX + radiusInner * cos (angle);
476- int16_t y0 = centerY + radiusInner * sin (angle);
477- int16_t x1 = centerX + dynamicOuter * cos (angle);
478- int16_t y1 = centerY + dynamicOuter * sin (angle);
479- myTFT.drawLine (x0, y0, x1, y1, color);
393+ myTFT.setTextColor (myTFT.RDLC_WHITE , myTFT.RDLC_BLACK );
394+ myTFT.drawArc (centerX, centerY, radius + 40 , 10 , 135 .0f , 45 .0f , myTFT.RDLC_GREEN );
395+ // Draw all menu nodes, initially selecting the first
396+ for (uint8_t i = 0 ; i < itemCount; ++i){
397+ drawItem (i, i == 0 );}
398+ uint8_t selected = 0 ;
399+ int8_t oldSelected = -1 ;
400+ // Draw pointer to initial selection
401+ drawPointer (selected, myTFT.RDLC_YELLOW );
402+ // inline label drawing
403+ myTFT.setFont (font_mega);
404+ myTFT.setTextColor (myTFT.RDLC_RED , myTFT.RDLC_YELLOW );
405+ myTFT.fillRectangle (centerX - 30 , centerY + radius + 35 , 80 , 16 , myTFT.RDLC_YELLOW );
406+ char buf[20 ];
407+ std::strncpy (buf, items[selected].label , sizeof (buf));
408+ buf[sizeof (buf) - 1 ] = ' \0 ' ;
409+ myTFT.writeCharString (centerX - 50 , centerY + radius + 35 , buf);
410+ // --- Main input loop ---
411+ while (true ) {
412+ int ch = getchar_timeout (1000 );
413+ if (ch == ' q' || ch == ' Q' ) break ;
414+ oldSelected = selected;
415+ if (ch == ' a' || ch == ' A' )
416+ selected = (selected + itemCount - 1 ) % itemCount;
417+ if (ch == ' d' || ch == ' D' )
418+ selected = (selected + 1 ) % itemCount;
419+ if (selected != oldSelected)
420+ {
421+ // Erase old pointer and node
422+ drawPointer (oldSelected, myTFT.RDLC_BLACK );
423+ drawItem (oldSelected, false );
424+ // Draw new pointer and node
425+ drawItem (selected, true );
426+ drawointer (selected, myTFT.RDLC_YELLOW );
427+ // Draw updated label below the new selection
428+ myTFT.setFont (font_mega);
429+ myTFT.setTextColor (myTFT.RDLC_RED , myTFT.RDLC_YELLOW );
430+ myTFT.fillRectangle (centerX - 30 , centerY + radius + 35 , 80 , 16 , myTFT.RDLC_YELLOW );
431+ std::strncpy (buf, items[selected].label , sizeof (buf));
432+ buf[sizeof (buf) - 1 ] = ' \0 ' ;
433+ myTFT.writeCharString (centerX - 50 , centerY + radius + 35 , buf);
434+ myTFT.setFont (font_default);
480435 }
481- // Center pulse
482- uint8_t pulseRadius = 5 + (rand () % 10 );
483- uint16_t pulseColor = rdlib_maths::generateColor (rand () % 128 );
484- myTFT.fillCircle (centerX, centerY, pulseRadius, pulseColor);
485- // Simulated BPM display
486- // char bpmBuf[12];
487- // snprintf(bpmBuf, sizeof(bpmBuf), "BPM %03d", 60 + rand() % 60);
488- // std::cout << "\r" << bpmBuf << std::flush;
489-
490- delayMilliSecRDL (timeDelay);
491- myTFT.fillScreen (myTFT.RDLC_BLACK );
492436 }
493-
494- std::cout << " Music Visualizer Dial end " << std::endl;
437+ myTFT. fillScreen (myTFT. RDLC_BLACK );
438+ std::cout << " Demo 3 Over " << std::endl;
495439}
496440
497- // Demo 5
441+ // Demo 4
498442void analogClockDemo (uint16_t countLimit)
499443{
500444 myTFT.fillScreen (myTFT.RDLC_BLACK );
@@ -553,7 +497,7 @@ void analogClockDemo(uint16_t countLimit)
553497 std::cout << " Clock Demo over : " <<std::endl;
554498}
555499
556- // Demo 6
500+ // Demo 5
557501void volumeKnobDemo (void )
558502{
559503 myTFT.fillScreen (myTFT.RDLC_BLACK );
0 commit comments