Calibration Class Implementation
In the constructor we first ensure that the Calibration dialog fills up the entire screen, has focus and will receive mouse events (the latter by making the dialog modal):
Calibration::Calibration()
{
QRect desktop = QApplication::desktop()->geometry();
desktop.moveTo(QPoint(0, 0));
setGeometry(desktop);
setFocusPolicy(Qt::StrongFocus);
setFocus();
setModal(true);
Then we initialize the screenPoints array:
int width = qt_screen->deviceWidth();
int height = qt_screen->deviceHeight();
int dx = width / 10;
int dy = height / 10;
QPoint *points = data.screenPoints;
points[QWSPointerCalibrationData::TopLeft] = QPoint(dx, dy);
points[QWSPointerCalibrationData::BottomLeft] = QPoint(dx, height - dy);
points[QWSPointerCalibrationData::BottomRight] = QPoint(width - dx, height - dy);
points[QWSPointerCalibrationData::TopRight] = QPoint(width - dx, dy);
points[QWSPointerCalibrationData::Center] = QPoint(width / 2, height / 2);
In order to specify the calibration, the screenPoints array must contain the screen coordinates for the logical positions represented by the QWSPointerCalibrationData::Location enum (e.g. QWSPointerCalibrationData::TopLeft). Since non-linearity is expected to increase on the edge of the screen, all points are kept 10 percent within the screen. The qt_screen pointer is a reference to the screen device. There can only be one screen device per application.
pressCount = 0;
}
Finally, we initialize the variable which keeps track of the number of mouse press events we have received.
Calibration::~Calibration()
{
}
The destructor is trivial.
int Calibration::exec()
{
QWSServer::mouseHandler()->clearCalibration();
grabMouse();
activateWindow();
int ret = QDialog::exec();
releaseMouse();
return ret;
}
The reimplementation of the QDialog::exec() slot is called from the main program.
First we clear the current calibration making the following mouse event delivered in raw device coordinates. Then we call the QWidget::grabMouse() function to make sure no mouse events are lost, and the QWidget::activateWindow() function to make the top-level widget containing this dialog, the active window. When the call to the QDialog::exec() base function returns, we call QWidget::releaseMouse() to release the mouse grab before the function returns.
void Calibration::paintEvent(QPaintEvent*)
{
QPainter p(this);
p.fillRect(rect(), Qt::white);
QPoint point = data.screenPoints[pressCount];
QSize screenSize(qt_screen->deviceWidth(), qt_screen->deviceHeight());
point = qt_screen->mapFromDevice(point, screenSize);
p.fillRect(point.x() - 6, point.y() - 1, 13, 3, Qt::black);
p.fillRect(point.x() - 1, point.y() - 6, 3, 13, Qt::black);
}
The QWidget::paintEvent() function is reimplemented to receive the widget's paint events. A paint event is a request to repaint all or parts of the widget. It can happen as a result of QWidget::repaint() or QWidget::update(), or because the widget was obscured and has now been uncovered, or for many other reasons. In our reimplementation of the function we simply draw a cross at the next point the user should press.
void Calibration::mouseReleaseEvent(QMouseEvent *event)
{
QSize screenSize(qt_screen->width(), qt_screen->height());
QPoint p = qt_screen->mapToDevice(event->pos(), screenSize);
data.devPoints[pressCount] = p;
if (++pressCount < 5)
repaint();
else
accept();
}
We then reimplement the QWidget::mouseReleaseEvent() function to receive the widget's move events, using the QMouseEvent object passed as parameter to find the coordinates the user pressed, and update the QWSPointerCalibrationData::devPoints array.
In order to complete the mapping between logical and physical coordinates, the devPoints array must contain the raw device coordinates for the logical positions represented by the QWSPointerCalibrationData::Location enum (e.g. QWSPointerCalibrationData::TopLeft)
We continue by drawing the next cross, or close the dialog by calling the QDialog::accept() slot if we have collected all the required coordinate samples.
void Calibration::accept()
{
Q_ASSERT(pressCount == 5);
QWSServer::mouseHandler()->calibrate(&data);
QDialog::accept();
}
Our reimplementation of the QDialog::accept() slot simply activate the new calibration data using the QWSMouseHandler::calibrate() function. We also use the Q_ASSERT() macro to ensure that the number of required samples are present.