@@ -361,16 +361,111 @@ QString PEHeaders::GetNameOfEnumerationMember(BinaryViewRef data, const std::str
361361}
362362
363363
364- HeaderWidget::HeaderWidget (QWidget* parent, const Headers& header) : QWidget(parent)
364+ HeaderWidget::HeaderWidget (QWidget* parent, const Headers& header) : QWidget(parent), m_headers(header)
365365{
366- QGridLayout* layout = new QGridLayout ();
367- layout->setContentsMargins (0 , 0 , 0 , 0 );
368- layout->setVerticalSpacing (1 );
366+ m_layout = new QGridLayout ();
367+ m_layout->setContentsMargins (0 , 0 , 0 , 0 );
368+ m_layout->setVerticalSpacing (1 );
369+ m_layout->setHorizontalSpacing (2 );
370+ setLayout (m_layout);
371+ m_currentColumns = (int )header.GetColumns ();
372+ m_pendingWidth = -1 ;
373+
374+ // Create timer for debouncing resize events
375+ m_resizeTimer = new QTimer (this );
376+ m_resizeTimer->setSingleShot (true );
377+ m_resizeTimer->setInterval (50 ); // 50ms delay after resize stops
378+ connect (m_resizeTimer, &QTimer::timeout, this , &HeaderWidget::performDelayedResize);
379+
380+ rebuildLayout ();
381+ }
382+
383+
384+ void HeaderWidget::resizeEvent (QResizeEvent* event)
385+ {
386+ QWidget::resizeEvent (event);
387+ updateColumns (this ->width ());
388+ }
389+
390+
391+ void HeaderWidget::updateColumns (int width)
392+ {
393+ m_pendingWidth = width;
394+ m_resizeTimer->start ();
395+ }
396+
397+
398+ void HeaderWidget::performDelayedResize ()
399+ {
400+ if (m_pendingWidth < 0 )
401+ return ;
402+
403+ int width = m_pendingWidth;
404+ m_pendingWidth = -1 ;
405+
406+ int desiredColumns;
407+
408+ // Add hysteresis to prevent thrashing when width oscillates near breakpoints
409+ if (m_currentColumns == 1 )
410+ {
411+ // Growing from 1 column: need to exceed threshold to switch
412+ if (width >= TriageBreakpoints::NARROW + 40 )
413+ desiredColumns = (width >= TriageBreakpoints::MEDIUM + 40 ) ? (int )m_headers.GetColumns () : 2 ;
414+ else
415+ desiredColumns = 1 ;
416+ }
417+ else if (m_currentColumns == 2 )
418+ {
419+ // From 2 columns: wider hysteresis band
420+ if (width < TriageBreakpoints::NARROW - 40 )
421+ desiredColumns = 1 ;
422+ else if (width >= TriageBreakpoints::MEDIUM + 40 )
423+ desiredColumns = (int )m_headers.GetColumns ();
424+ else
425+ desiredColumns = 2 ;
426+ }
427+ else
428+ {
429+ // Shrinking from 3 columns: need to fall below threshold to switch
430+ if (width < TriageBreakpoints::NARROW - 40 )
431+ desiredColumns = 1 ;
432+ else if (width < TriageBreakpoints::MEDIUM - 40 )
433+ desiredColumns = 2 ;
434+ else
435+ desiredColumns = (int )m_headers.GetColumns ();
436+ }
437+
438+ if (desiredColumns != m_currentColumns)
439+ {
440+ m_currentColumns = desiredColumns;
441+ rebuildLayout ();
442+ }
443+ }
444+
445+
446+ void HeaderWidget::rebuildLayout ()
447+ {
448+ // Disable updates during rebuild to prevent flickering
449+ setUpdatesEnabled (false );
450+
451+ // Clear existing layout
452+ QLayoutItem* item;
453+ while ((item = m_layout->takeAt (0 )) != nullptr )
454+ {
455+ if (item->widget ())
456+ {
457+ item->widget ()->hide (); // Hide before deletion to reduce flicker
458+ item->widget ()->deleteLater (); // Use deleteLater() to safely delete during events
459+ }
460+ delete item;
461+ }
462+
463+ // Rebuild with current column count
369464 int row = 0 ;
370465 int col = 0 ;
371- for (auto & field : header .GetFields ())
466+ for (auto & field : m_headers .GetFields ())
372467 {
373- layout ->addWidget (new QLabel (field.title + " : " ), row, col * 3 );
468+ m_layout ->addWidget (new QLabel (field.title + " : " ), row, col * 3 );
374469
375470 // For text fields with multiple values, join them with newlines for copying
376471 QString copyText;
@@ -401,18 +496,31 @@ HeaderWidget::HeaderWidget(QWidget* parent, const Headers& header) : QWidget(par
401496 copyLabel->setCopyText (copyText);
402497 label = copyLabel;
403498 }
404- layout ->addWidget (label, row, col * 3 + 1 );
499+ m_layout ->addWidget (label, row, col * 3 + 1 );
405500 row++;
406501 }
407- if ((header. GetColumns () > 1 ) && (row >= (int )header .GetRowsPerColumn ())
408- && ((col + 1 ) < ( int )header. GetColumns () ))
502+ if ((m_currentColumns > 1 ) && (row >= (int )m_headers .GetRowsPerColumn ())
503+ && ((col + 1 ) < m_currentColumns ))
409504 {
410505 row = 0 ;
411506 col++;
412507 }
413508 }
414- for (col = 1 ; col < (int )header.GetColumns (); col++)
415- layout->setColumnMinimumWidth (col * 3 - 1 , UIContext::getScaledWindowSize (20 , 20 ).width ());
416- layout->setColumnStretch ((int )header.GetColumns () * 3 - 1 , 1 );
417- setLayout (layout);
509+
510+ // Clear all column stretches and minimum widths first
511+ for (col = 0 ; col < 9 ; col++) // Max 3 columns * 3 grid columns each
512+ {
513+ m_layout->setColumnStretch (col, 0 );
514+ m_layout->setColumnMinimumWidth (col, 0 );
515+ }
516+
517+ // Set spacing columns to minimum width
518+ for (col = 1 ; col < m_currentColumns; col++)
519+ m_layout->setColumnMinimumWidth (col * 3 - 1 , UIContext::getScaledWindowSize (20 , 20 ).width ());
520+
521+ // Set last column to stretch
522+ m_layout->setColumnStretch (m_currentColumns * 3 - 1 , 1 );
523+
524+ // Re-enable updates and force a single repaint
525+ setUpdatesEnabled (true );
418526}
0 commit comments