-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathdocpagelabel.cpp
More file actions
251 lines (227 loc) · 11.5 KB
/
docpagelabel.cpp
File metadata and controls
251 lines (227 loc) · 11.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
// Copyright 2023 by Linwood Ferguson, licensed under GNU GPLv3
#include "docpagelabel.h"
#include "mainwindow.h"
#include <QObject>
#include <QImage>
#include <QThread>
#include <QPainter>
#include <QBitmap>
#include <QColor>
#include <cassert>
#include "oursettings.h"
// Note terminology:
// The transition is the page contents appearing somewhere
// The highlight is the, occasional, surrounding boarder to call one's attention to the page change
// Transitions will influence the type of highlight shown but they are done in different QLabels overlaid
docPageLabel::docPageLabel(QWidget *parent,MainWindow* mp) : QLabel(parent)
{
// Widget to display one page where/how we want it
qDebug() << " in constructor";
ourParent = parent;
mParent = mp;
pageHighlightHeight=mParent->ourSettingsPtr->getSetting("pageHighlightHeight").toInt();
pageHighlightDelay=mParent->ourSettingsPtr->getSetting("pageHighlightDelay").toInt();
pageTurnDelay=mParent->ourSettingsPtr->getSetting("pageTurnDelay").toInt();
ourOverlay.setParent(this);
ourOverlay.hide();
ourHighlightOverlay.setParent(this);
ourHighlightOverlay.hide();
ourHighlightOverlay.setAttribute(Qt::WA_TranslucentBackground);
our2ndHighlightOverlay.setParent(this);
our2ndHighlightOverlay.hide();
our2ndHighlightOverlay.setAttribute(Qt::WA_TranslucentBackground);
ourOverlayTimer.setInterval(pageTurnDelay);
ourOverlayTimer.setSingleShot(true);
connect(&ourOverlayTimer, &QTimer::timeout,
[=]()
{
qDebug() << "Hiding overlay";
ourOverlay.hide();
}
);
ourHighlightShowTimer.setSingleShot(true);
connect(&ourHighlightShowTimer, &QTimer::timeout,
[=]()
{
qDebug() << "Showing highlight";
ourHighlightOverlay.show();
}
);
ourHighlightHideTimer.setSingleShot(true);
connect(&ourHighlightHideTimer, &QTimer::timeout,
[=]()
{
qDebug() << "Hiding highlight";
ourHighlightOverlay.hide();
}
);
our2ndHighlightShowTimer.setSingleShot(true);
connect(&our2ndHighlightShowTimer, &QTimer::timeout,
[=]()
{
qDebug() << "Showing 2nd highlight";
our2ndHighlightOverlay.show();
}
);
our2ndHighlightHideTimer.setSingleShot(true);
connect(&our2ndHighlightHideTimer, &QTimer::timeout,
[=]()
{
qDebug() << "Hiding 2nd highlight";
our2ndHighlightOverlay.hide();
}
);
newImageIsBlank = false;
oldImageIsBlank = false;
}
docPageLabel::~docPageLabel()
{
qDebug() << "in destructor";
// clean up????
}
void docPageLabel::placeImage(docPageLabel::docTransition thisTransition, QString color)
{
QImage* blankImage = new QImage(this->width(), this->height(), QImage::Format_RGB32);
blankImage->fill(color);
qDebug() << "Switching placement request for blank image as it is outside of page range";
newImageIsBlank = true; // This will remember that the image was blank (too hard to check the pixmap itself
placeImage(thisTransition, blankImage, color);
}
void docPageLabel::placeImage(docPageLabel::docTransition thisTransition, QImage* newImageBuffer, QString color)
{
// This handles (some) transitions by putting an overlay with the OLD image
// on top, where it can be left for a period of time, but the NEW is the
// permanent, underlying image. If there is no transition then no overlay is created.
//
// Possible transitions:
//
// noTransition Immediately display new (but there is a border transition briefly)
// halfPage The BOTTOM half of the old page remains shown for transition time
// Note this means the overlay is a half screen down
// fullPage Page will remain unchanged for transition time, then brief highlight
// fullPageNow Page is displayed immediately, with brief highlight
assert(newImageBuffer);
qDebug() << "Entered with transition type = " << thisTransition
<< ", and image of size " << newImageBuffer->width() << "x" << newImageBuffer->height()
<< ", container is " << this->width() << "x" << this->height();
// Just kill any timers and hide any overlays we have now as we will make new
HideAnyInProgressTransitions();
// We form an image here of what we need to display with suitable background and centered, the image in pageImages
// does not have these borders. The new image is formed first so we can copy it into the overlay if needed
QImage newImage(this->width(), this->height(),QImage::Format_ARGB32_Premultiplied);
newImage.fill(QColor(color)); // We have to paint this not transparent since pages are different sizes
// We should only be scaling down never up(pdfDocument takes care of that),
// We do need need to recalculate scale with possibility we are scalling down
float scale = std::min((float)(this->width()) / (float)(newImageBuffer->width()),
(float)(this->height()) / (float)(newImageBuffer->height()));
// If we aim for a scale of 1, generally scale at this point will be 1 or very slightly higher; but never
// scale up. If we were doubling scale for precision on notational scores, this will come out at 1/2 or so, etc.
scale = std::min((float)1.0,scale); // Never scale up
qDebug() << "Scale of drawImage for new image (should be <= 1, ideally == 1 in play mode for quality) = " << scale;
int newW = newImageBuffer->width() * scale;
int newH = newImageBuffer->height() * scale;
int newX = (this->width() - newW)/2;
int newY = (this->height() - newH)/2;
QPainter pNew(&newImage);
pNew.setRenderHint(QPainter::SmoothPixmapTransform);
pNew.setRenderHint(QPainter::Antialiasing);
pNew.drawImage( QRectF (newX, newY, newW, newH), *newImageBuffer); // This implicitly draws the whole from image, scaling if needed
// While we have all the new image info, go ahead and build the highlight overlay(s)
// according to the transition type. This is just the highlight overlay, not the
// page transition overlay which comes next.
if(!newImageIsBlank || thisTransition == noTransition) // if the new page is blank there is no highlight regardless, also if no transition
{
QImage frameImage(QImage(this->width(), this->height(), QImage::Format_ARGB32));
frameImage.fill(Qt::transparent);
QPainter hp(&frameImage);
hp.setBrush(QBrush(Qt::green,Qt::Dense4Pattern));
hp.setPen(Qt::NoPen);
if(thisTransition == fullPageNow || thisTransition == fullPage)
{
hp.drawRect(newX,newY,newW,pageHighlightHeight);
hp.drawRect(newX,newY,pageHighlightHeight,newH);
hp.drawRect(newX,newY + newH-pageHighlightHeight,newW,pageHighlightHeight);
hp.drawRect(newX + newW-pageHighlightHeight,newY,pageHighlightHeight,newH);
if(thisTransition == fullPageNow)
{
ourHighlightShowTimer.setInterval(1);
ourHighlightHideTimer.setInterval(1 + pageHighlightDelay);
}
else // fullPage
{
ourHighlightShowTimer.setInterval(pageTurnDelay);
ourHighlightHideTimer.setInterval(pageTurnDelay + pageHighlightDelay);
}
ourHighlightOverlay.setGeometry(0,0,this->geometry().width(),this->geometry().height()); // lay over ourself
ourHighlightOverlay.setPixmap(QPixmap::fromImage(frameImage));
ourHighlightShowTimer.start();
ourHighlightHideTimer.start();
}
else if (thisTransition == halfPage)
{
// First draw top half which appears immediately
hp.drawRect(newX,newY,newW,pageHighlightHeight); // top left across
hp.drawRect(newX,newY,pageHighlightHeight,newH/2); // top left down
hp.drawRect(newX,newY + newH/2 -pageHighlightHeight,newW,pageHighlightHeight); // bottom left across
hp.drawRect(newX + newW - pageHighlightHeight,newY,pageHighlightHeight,newH/2); // top right down
ourHighlightShowTimer.setInterval(1);
ourHighlightHideTimer.setInterval(1 + pageHighlightDelay);
ourHighlightOverlay.setGeometry(0,0,this->geometry().width(),this->geometry().height()); // lay over ourself
ourHighlightOverlay.setPixmap(QPixmap::fromImage(frameImage));
// now bottom half which appears later
QImage frame2ndImage(QImage(this->width(), this->height(), QImage::Format_ARGB32));
frame2ndImage.fill(Qt::transparent);
QPainter hp2(&frame2ndImage);
hp2.setBrush(QBrush(Qt::green,Qt::Dense4Pattern));
hp2.setPen(Qt::NoPen);
hp2.drawRect(newX,newY + newH/2,newW,pageHighlightHeight);
hp2.drawRect(newX,newY + newH/2,pageHighlightHeight,newH/2);
hp2.drawRect(newX,newY + newH-pageHighlightHeight,newW,pageHighlightHeight);
hp2.drawRect(newX + newW-pageHighlightHeight,newY + newH/2,pageHighlightHeight,newH/2);
our2ndHighlightShowTimer.setInterval(pageTurnDelay);
our2ndHighlightHideTimer.setInterval(pageTurnDelay + pageHighlightDelay);
our2ndHighlightOverlay.setGeometry(0,0,this->geometry().width(),this->geometry().height()); // lay over ourself
our2ndHighlightOverlay.setPixmap(QPixmap::fromImage(frame2ndImage));
ourHighlightShowTimer.start();
ourHighlightHideTimer.start();
our2ndHighlightShowTimer.start();
our2ndHighlightHideTimer.start();
}
}
// This is the page image transition overlay, if needed.
// This is the OLD image, the new image is always placed inside "this", so to show it
// we just remove the ourOverlay at the right time.
if((thisTransition != noTransition && thisTransition != fullPageNow) && !this->pixmap().isNull() && !oldImageIsBlank) // this latter is still the old image; if none no transition regardless
{
ourOverlay.setGeometry(0,0,this->geometry().width(),this->geometry().height()); // Position directly over
QPixmap tmpPixmap = this->pixmap().copy(); // grab the old image -- the overlay is what is OLD not new, new will be underneath
if(thisTransition == halfPage) // we have to replace the top half
{
// For overlay just divide it in half do not rescale, and paint new over old
QPainter pOld(&tmpPixmap);
QRectF sameFromTo(0,0,tmpPixmap.width(), tmpPixmap.height()/2);
pOld.drawImage(sameFromTo,newImage,sameFromTo);
}
//else thisTransition == fullPage (but not fullPageNow)
ourOverlay.setPixmap(tmpPixmap);
ourOverlay.show();
qDebug() << "Starting timer to hide overlay";
ourOverlayTimer.start();
}
this->setPixmap(QPixmap::fromImage(newImage));
// This awkward technique records in this instance whether the image now displayed is blank
oldImageIsBlank = newImageIsBlank; // remember what we just loaded
newImageIsBlank = false; // reseet for next call, since in this variant we can't tell directly
}
void docPageLabel::HideAnyInProgressTransitions()
{
// Used to interrupt transitions if a sudden change occurs (e.g. a subsequent page turn before this finished)
ourOverlay.hide();
ourHighlightOverlay.hide();
our2ndHighlightOverlay.hide();
ourOverlayTimer.stop();
ourHighlightShowTimer.stop();
ourHighlightHideTimer.stop();
our2ndHighlightShowTimer.stop();
our2ndHighlightHideTimer.stop();
}