Skip to content

Commit c7fa60a

Browse files
author
Local Development
committed
Fix oscilloscope dynamic scaling for Windows DPI support and proper Y/C rendering
1 parent de3a9bc commit c7fa60a

2 files changed

Lines changed: 76 additions & 24 deletions

File tree

tools/ld-analyse/oscilloscopedialog.cpp

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ OscilloscopeDialog::OscilloscopeDialog(QWidget *parent) :
3939
lastScopeX = 0;
4040
lastScopeY = 0;
4141
scopeWidth = 0;
42+
scopeHeight = 512; // Initial default height
43+
devicePixelRatio = 1.0;
4244

4345
// Configure the GUI
4446
ui->xCoordSpinBox->setMinimum(0);
@@ -71,14 +73,25 @@ void OscilloscopeDialog::showTraceImage(TbcSource::ScanLineData scanLineData, qi
7173
lastScopeX = xCoord;
7274
lastScopeY = yCoord;
7375

76+
// Calculate optimal scope height based on widget size and DPI
77+
scopeHeight = getOptimalScopeHeight();
78+
devicePixelRatio = ui->scopeLabel->devicePixelRatioF();
79+
80+
qDebug() << "OscilloscopeDialog::showTraceImage(): Widget height =" << ui->scopeLabel->height()
81+
<< "Calculated scope height =" << scopeHeight << "DPI ratio =" << devicePixelRatio;
82+
7483
// Get the raw field data for the selected line
7584
QImage traceImage = getFieldLineTraceImage(scanLineData, lastScopeX);
7685

7786
// Add the QImage to the QLabel in the dialogue
7887
ui->scopeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
7988
ui->scopeLabel->setAlignment(Qt::AlignCenter);
8089
ui->scopeLabel->setScaledContents(true);
81-
ui->scopeLabel->setPixmap(QPixmap::fromImage(traceImage));
90+
91+
// Set pixmap with proper high-DPI support
92+
QPixmap pixmap = QPixmap::fromImage(traceImage);
93+
pixmap.setDevicePixelRatio(devicePixelRatio);
94+
ui->scopeLabel->setPixmap(pixmap);
8295

8396
// Update the X coordinate spinbox
8497
ui->xCoordSpinBox->setMaximum(maximumX - 1);
@@ -110,14 +123,24 @@ QImage OscilloscopeDialog::getFieldLineTraceImage(TbcSource::ScanLineData scanLi
110123
bool showC = ui->CcheckBox->isChecked();
111124
bool showDropouts = ui->dropoutsCheckBox->isChecked();
112125

113-
// These are fixed, but may be changed to options later
114-
qint32 scopeHeight = 2048;
126+
// Use dynamic scope height - ensure it's been calculated
127+
qint32 imageHeight = scopeHeight;
128+
if (imageHeight <= 0) {
129+
qWarning() << "OscilloscopeDialog::getFieldLineTraceImage(): scopeHeight not set, using default 512";
130+
imageHeight = 512;
131+
}
132+
133+
// Clamp to reasonable bounds for image generation
134+
if (imageHeight < 256) imageHeight = 256;
135+
if (imageHeight > 4096) imageHeight = 4096;
136+
115137
scopeWidth = scanLineData.fieldWidth;
138+
qint32 scopeScale = 65536 / imageHeight;
116139

117-
qint32 scopeScale = 65536 / scopeHeight;
140+
qDebug() << "OscilloscopeDialog::getFieldLineTraceImage(): Using imageHeight =" << imageHeight << "scopeScale =" << scopeScale;
118141

119142
// Define image with width, height and format
120-
QImage scopeImage(scopeWidth, scopeHeight, QImage::Format_RGB888);
143+
QImage scopeImage(scopeWidth, imageHeight, QImage::Format_RGB888);
121144
QPainter scopePainter;
122145

123146
// Ensure we have valid data
@@ -138,11 +161,11 @@ QImage OscilloscopeDialog::getFieldLineTraceImage(TbcSource::ScanLineData scanLi
138161
// Add the black and white levels
139162
// Note: For PAL this should be black at 64 and white at 211
140163

141-
// Scale to 512 pixel height
142-
qint32 blackIre = scopeHeight - (scanLineData.blackIre / scopeScale);
143-
qint32 whiteIre = scopeHeight - (scanLineData.whiteIre / scopeScale);
164+
// Scale to dynamic pixel height
165+
qint32 blackIre = imageHeight - (scanLineData.blackIre / scopeScale);
166+
qint32 whiteIre = imageHeight - (scanLineData.whiteIre / scopeScale);
144167
qint32 midPointIre = scanLineData.blackIre + ((scanLineData.whiteIre - scanLineData.blackIre) / 2);
145-
midPointIre = scopeHeight - (midPointIre / scopeScale);
168+
midPointIre = imageHeight - (midPointIre / scopeScale);
146169

147170
scopePainter.setPen(Qt::white);
148171
scopePainter.drawLine(0, blackIre, scanLineData.fieldWidth, blackIre);
@@ -156,11 +179,11 @@ QImage OscilloscopeDialog::getFieldLineTraceImage(TbcSource::ScanLineData scanLi
156179

157180
// Draw the indicator lines
158181
scopePainter.setPen(Qt::blue);
159-
scopePainter.drawLine(scanLineData.colourBurstStart, 0, scanLineData.colourBurstStart, scopeHeight);
160-
scopePainter.drawLine(scanLineData.colourBurstEnd, 0, scanLineData.colourBurstEnd, scopeHeight);
182+
scopePainter.drawLine(scanLineData.colourBurstStart, 0, scanLineData.colourBurstStart, imageHeight);
183+
scopePainter.drawLine(scanLineData.colourBurstEnd, 0, scanLineData.colourBurstEnd, imageHeight);
161184
scopePainter.setPen(Qt::cyan);
162-
scopePainter.drawLine(scanLineData.activeVideoStart, 0, scanLineData.activeVideoStart, scopeHeight);
163-
scopePainter.drawLine(scanLineData.activeVideoEnd, 0, scanLineData.activeVideoEnd, scopeHeight);
185+
scopePainter.drawLine(scanLineData.activeVideoStart, 0, scanLineData.activeVideoStart, imageHeight);
186+
scopePainter.drawLine(scanLineData.activeVideoEnd, 0, scanLineData.activeVideoEnd, imageHeight);
164187

165188
// Get the signal data
166189
const QVector<qint32> &signalDataYC = scanLineData.composite; // Composite signal
@@ -179,8 +202,8 @@ QImage OscilloscopeDialog::getFieldLineTraceImage(TbcSource::ScanLineData scanLi
179202
qint32 lastSignalLevelYC = 0;
180203
for (qint32 xPosition = 0; xPosition < scanLineData.fieldWidth; xPosition++) {
181204
if (showYC) {
182-
// Scale (to 0-512) and invert
183-
qint32 signalLevelYC = scopeHeight - (signalDataYC[xPosition] / scopeScale);
205+
// Scale (to dynamic height) and invert
206+
qint32 signalLevelYC = imageHeight - (signalDataYC[xPosition] / scopeScale);
184207

185208
if (xPosition != 0) {
186209
// Non-active video area YC is yellow, active is white
@@ -204,8 +227,8 @@ QImage OscilloscopeDialog::getFieldLineTraceImage(TbcSource::ScanLineData scanLi
204227
qint32 lastSignalLevelC = 0;
205228
for (qint32 xPosition = scanLineData.activeVideoStart; xPosition < scanLineData.activeVideoEnd; xPosition++) {
206229
if (showC && scanLineData.isActiveLine) {
207-
// Scale (to 0-512) and invert
208-
qint32 signalLevelC = (scopeHeight - (signalDataC[xPosition] / scopeScale)) - (scopeHeight - midPointIre);
230+
// Scale (to dynamic height) and invert
231+
qint32 signalLevelC = (imageHeight - (signalDataC[xPosition] / scopeScale)) - (imageHeight - midPointIre);
209232

210233
if (xPosition != scanLineData.activeVideoStart) {
211234
// Draw a line from the last Y signal to the current one (signal green, out of range in yellow)
@@ -219,8 +242,8 @@ QImage OscilloscopeDialog::getFieldLineTraceImage(TbcSource::ScanLineData scanLi
219242
}
220243

221244
if (showY && scanLineData.isActiveLine) {
222-
// Scale (to 0-512) and invert
223-
qint32 signalLevelY = scopeHeight - (signalDataY[xPosition] / scopeScale);
245+
// Scale (to dynamic height) and invert
246+
qint32 signalLevelY = imageHeight - (signalDataY[xPosition] / scopeScale);
224247

225248
if (xPosition != scanLineData.activeVideoStart) {
226249
// Draw a line from the last Y signal to the current one (signal white, out of range in red)
@@ -236,13 +259,36 @@ QImage OscilloscopeDialog::getFieldLineTraceImage(TbcSource::ScanLineData scanLi
236259

237260
// Draw the picture dot position line
238261
scopePainter.setPen(QColor(0, 255, 0, 127));
239-
scopePainter.drawLine(pictureDot, 0, pictureDot, scopeHeight);
262+
scopePainter.drawLine(pictureDot, 0, pictureDot, imageHeight);
240263

241264
// Return the QImage
242265
scopePainter.end();
243266
return scopeImage;
244267
}
245268

269+
// Calculate optimal scope height based on widget size and DPI
270+
qint32 OscilloscopeDialog::getOptimalScopeHeight()
271+
{
272+
// Get the widget's physical size
273+
qint32 widgetHeight = ui->scopeLabel->height();
274+
275+
qDebug() << "OscilloscopeDialog::getOptimalScopeHeight(): Widget height =" << widgetHeight;
276+
277+
// If widget hasn't been sized yet, use a reasonable default
278+
if (widgetHeight < 50) {
279+
qDebug() << "OscilloscopeDialog::getOptimalScopeHeight(): Using default height 512 (widget too small)";
280+
return 512;
281+
}
282+
283+
// Clamp to reasonable bounds (between 256 and 4096 pixels)
284+
if (widgetHeight > 2048) {
285+
return 4096; // Maximum quality to avoid memory waste
286+
} else {
287+
// Scale height proportionally: each display pixel gets ~2 image pixels for quality
288+
return qMax(512, widgetHeight * 2);
289+
}
290+
}
291+
246292
// GUI signal handlers ------------------------------------------------------------------------------------------------
247293

248294
void OscilloscopeDialog::on_previousPushButton_clicked()
@@ -328,17 +374,20 @@ void OscilloscopeDialog::mouseMoveEvent(QMouseEvent *event)
328374
// Handle a click on the scope with shift held down, to select a level
329375
void OscilloscopeDialog::mouseLevelSelect(qint32 oY)
330376
{
331-
double unscaledYR = (65536.0 / static_cast<double>(ui->scopeLabel->height())) * static_cast<double>(oY);
377+
// Convert widget pixel coordinate to image pixel coordinate, accounting for DPI
378+
double scaleFactor = static_cast<double>(scopeHeight) / static_cast<double>(ui->scopeLabel->height());
379+
double unscaledYR = scaleFactor * static_cast<double>(oY);
332380

333-
qint32 level = qBound(0, 65535 - static_cast<qint32>(unscaledYR), 65535);
381+
qint32 level = qBound(0, 65535 - static_cast<qint32>(unscaledYR * (65536.0 / static_cast<double>(scopeHeight))), 65535);
334382
emit scopeLevelSelect(level);
335383
}
336384

337385
// Handle a click on the scope without shift held down, to select a sample
338386
void OscilloscopeDialog::mousePictureDotSelect(qint32 oX)
339387
{
340-
double unscaledXR = (static_cast<double>(scopeWidth) /
341-
static_cast<double>(ui->scopeLabel->width())) * static_cast<double>(oX);
388+
// Convert widget pixel coordinate to image pixel coordinate, accounting for DPI
389+
double scaleFactor = static_cast<double>(scopeWidth) / static_cast<double>(ui->scopeLabel->width());
390+
double unscaledXR = scaleFactor * static_cast<double>(oX);
342391

343392
qint32 unscaledX = static_cast<qint32>(unscaledXR);
344393
if (unscaledX > scopeWidth - 1) unscaledX = scopeWidth - 1;

tools/ld-analyse/oscilloscopedialog.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,13 @@ private slots:
7373
qint32 scopeWidth;
7474
qint32 lastScopeX;
7575
qint32 lastScopeY;
76+
qint32 scopeHeight; // Dynamic height based on widget size
77+
qreal devicePixelRatio; // DPI scaling factor
7678

7779
QImage getFieldLineTraceImage(TbcSource::ScanLineData scanLineData, qint32 pictureDot);
7880
void mouseLevelSelect(qint32 oY);
7981
void mousePictureDotSelect(qint32 oX);
82+
qint32 getOptimalScopeHeight(); // Calculate optimal height based on widget size
8083
};
8184

8285
#endif // OSCILLOSCOPEDIALOG_H

0 commit comments

Comments
 (0)