1 /* PCDM Login Manager:
2 * Written by Ken Moore (ken@pcbsd.org) 2012/2013
3 * Copyright(c) 2013 by the PC-BSD Project
4 * Available under the 3-clause BSD license
5 */
6
7 /*
8 Sub-classed fancy widget for selecting a desktop environment
9 */
10
11 #include "fancySwitcher.h"
12
FancySwitcher(QWidget * parent,bool horizontal)13 FancySwitcher::FancySwitcher(QWidget* parent,bool horizontal) : QWidget(parent)
14 {
15 //Set the default values for the current item
16 idL.clear(); icL.clear();
17 item=-1; oldItem=0; //default values for the current/old item number
18 frames=-1; //smoothest animation possible (1 pixel at a time)
19 //Save whether it is a horizontal or vertical display
20 isHorizontal = horizontal;
21 //Set the default size for the images
22 iconSize = 64; //default all icons in the viewer to 64x64 (can be changed later)
23 //Create the Grid layout
24 QGridLayout* layout = new QGridLayout();
25 //Add the buttons to the grid (back is always left/up)
26 pushForward = new QPushButton;
27 pushBack = new QPushButton;
28 pushForward->setIconSize(QSize(iconSize/2,iconSize/2));
29 pushBack->setIconSize(QSize(iconSize/2,iconSize/2));
30
31 textLabel = new QLabel;
32 textLabel->setAlignment(Qt::AlignCenter);
33
34 iconViewer = new QGraphicsView();
35 iconViewer->setInteractive(false);
36 iconViewer->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
37 iconViewer->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
38 iconViewer->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
39 if(isHorizontal){
40 iconViewer->setFixedSize(2.5*iconSize,iconSize+2);
41 pushBack->setIcon(QIcon(":images/left.png"));
42 pushBack->setShortcut(tr("Alt+Left"));
43 pushForward->setIcon(QIcon(":images/right.png"));
44 pushForward->setShortcut(tr("Alt+Right"));
45 layout->addWidget(pushBack,1,1);
46 layout->addWidget(iconViewer,1,2);
47 layout->addWidget(pushForward,1,3);
48 layout->addWidget(textLabel,2,1,1,3);
49 }else{ //vertical
50 iconViewer->setFixedSize(iconSize+2,2.5*iconSize);
51 pushBack->setIcon(QIcon(":images/up.png"));
52 pushBack->setShortcut(tr("Alt+Up"));
53 pushForward->setIcon(QIcon(":images/down.png"));
54 pushForward->setShortcut(tr("Alt+Down"));
55 layout->addWidget(pushBack,1,1);
56 layout->addWidget(iconViewer,2,1);
57 layout->addWidget(textLabel,3,1);
58 layout->addWidget(pushForward,4,1);
59 }
60 //set this layout as the layout for the FancySwitcher
61 this->setLayout(layout);
62 //connect the buttons to their appropriate slots
63 connect(pushBack,SIGNAL(clicked()),this,SLOT(slotPushBack()));
64 connect(pushForward,SIGNAL(clicked()),this,SLOT(slotPushForward()));
65
66 //Create the default scene for the iconViewer
67 updateIconViewer();
68 //Enable/disable the forward/back buttons as appropriate
69 checkButtons();
70 }
71
~FancySwitcher()72 FancySwitcher::~FancySwitcher(){
73 }
74
updateIconViewer()75 void FancySwitcher::updateIconViewer(){
76 //detect the base dimensions
77 int xsize,ysize;
78 if(isHorizontal){
79 xsize = (idL.length()+1+(idL.length()-1)*5.0/4)*iconSize;
80 ysize = iconSize;
81 }else{ //vertical
82 xsize = iconSize;
83 ysize = (idL.length()+1+(idL.length()-1)*5.0/4)*iconSize;
84 }
85 //qDebug() << "scene dimensions:" << xsize << ysize;
86 //Create the scene with the proper dimensions
87 scene = new QGraphicsScene(0,0,xsize,ysize);
88 //Fill the scene with the given images
89 int offset = iconSize*3/4; //initial offset ( (viewer width-iconsize)/2 )
90 for(int i=0; i<idL.length(); i++){
91 //qDebug() << "offset" << offset;
92 if(isHorizontal){
93 icL[i]->setOffset(offset,0);
94 }else{
95 icL[i]->setOffset(0,offset);
96 }
97 scene->addItem(icL[i]);
98 offset = offset + 5*iconSize/4; //have a 1/4 iconsize spacing between icons
99 }
100 //set the iconViewer to display the scene
101 iconViewer->setScene(scene);
102 displayCurrentItem(false);
103
104 }
105
displayCurrentItem(bool showAnimation)106 void FancySwitcher::displayCurrentItem(bool showAnimation){
107 //Check that the new item is valid
108 //if( (item >= idL.length()) || (item < 0) ){item = oldItem; return;} //reset to the previous value and don't change the display
109
110 if(item == -1){
111 iconViewer->centerOn(0,0);
112 iconViewer->show();
113 return;
114 }
115 //Get the current/old display pixel
116 int cPixel = (1 + oldItem*5.0/4)*iconSize;
117 //Get the new/desired display pixel
118 int tPixel = (1 + item*5.0/4)*iconSize;
119 //detect if we are moving back/forward
120 bool moveForward = true;
121 if(tPixel < cPixel){ moveForward = false; }
122 if(tPixel == cPixel){ showAnimation = false; } //same item, skip the animation loop and just refresh
123 //qDebug() << "displayItem:" << item << oldItem << cPixel << tPixel << moveForward;
124 //Show the scrolling animation if desired
125 if(showAnimation && (frames!=0)){
126 int pixchange = 1;
127 if(frames > 0){ pixchange=abs(tPixel-cPixel)/frames; } //draw fewer frames per animation
128
129 if(moveForward){
130 while(cPixel < (tPixel-pixchange+1)){
131 cPixel += pixchange;
132 if(isHorizontal){
133 iconViewer->centerOn(cPixel,0);
134 }else{
135 iconViewer->centerOn(0,cPixel);
136 }
137 iconViewer->show();
138 QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 22);
139 }
140 }else{
141 while(cPixel > (tPixel+pixchange-1)){
142 cPixel -= pixchange;
143 if(isHorizontal){
144 iconViewer->centerOn(cPixel,0);
145 }else{
146 iconViewer->centerOn(0,cPixel);
147 }
148 iconViewer->show();
149 QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 22);
150 }
151 }
152 iconViewer->centerOn(icL[item]);
153 iconViewer->show();
154 }else{
155 //Just center on the desired item (skip animation)
156 iconViewer->centerOn(icL[item]);
157 iconViewer->show();
158 }
159
160 //Save the (now) current item as the old item for animation purposes later
161 oldItem = item;
162 textLabel->setText(idL[item]); //set the info text
163 }
164
checkButtons()165 void FancySwitcher::checkButtons(){
166 //Sanity check the current item value
167 if(item > (idL.length()-1)){ item = idL.length()-1; }
168 if(item < -1){ item = -1; }
169 //Enable/Disable the pushbuttons as appropriate
170 if(item == (idL.length()-1)){ pushForward->setEnabled(false); }
171 else{ pushForward->setEnabled(true); }
172 if(item < 1){ pushBack->setEnabled(false); }
173 else{ pushBack->setEnabled(true); };
174 }
175
slotPushBack()176 void FancySwitcher::slotPushBack(){
177 item--;
178 if(item < 0){ item = 0; } //cannot go lower than the first item
179 displayCurrentItem(true); //show animation of changing items
180 checkButtons();
181 emit itemChanged();
182 emit itemChanged(idL[item]);
183 }
184
slotPushForward()185 void FancySwitcher::slotPushForward(){
186 item++;
187 if(item >= idL.length()){ item = idL.length()-1; } //cannot go higher than the last item
188 displayCurrentItem(true);
189 checkButtons();
190 emit itemChanged();
191 emit itemChanged(idL[item]);
192 }
193
194 //-----------------------------
195 // PUBLIC FUNCTIONS
196 //-----------------------------
addItem(QString id,QString icon,QString tooltip)197 void FancySwitcher::addItem(QString id, QString icon, QString tooltip){
198 if(!QFile::exists(icon)){
199 qDebug() << "FancySwitcher: invalid icon file" << icon;
200 return;
201 }
202 if(idL.indexOf(id)==-1){
203 idL << id;
204 icL << new QGraphicsPixmapItem(QPixmap(icon).scaled(iconSize,iconSize));
205 if(!tooltip.isEmpty()){
206 int index = idL.indexOf(id);
207 icL[index]->setToolTip(tooltip);
208 }
209 }
210 if(item==-1){item = 0;} //There is now an item that can be selected
211 updateIconViewer();
212 checkButtons();
213 }
214
addItems(QStringList idList,QStringList iconList,QStringList tooltipList)215 void FancySwitcher::addItems(QStringList idList, QStringList iconList, QStringList tooltipList){
216 //Check that all the lists are the same length
217 if(!( (idList.length()==iconList.length()) && (idList.length()==tooltipList.length()) )){
218 qDebug() << "FancySwitcher: item lists are not equal length";
219 return;
220 }
221 //Check each item and add it to the list if applicable
222 for(int i=0; i<idList.length(); i++){
223 if(!QFile::exists(iconList[i])){
224 qDebug() << "FancySwitcher: invalid icon file" << iconList[i];
225 return;
226 }else{
227 if(idL.indexOf(idList[i].toLower()) == -1){
228 idL << idList[i];
229 icL << new QGraphicsPixmapItem(QPixmap(iconList[i]).scaled(iconSize,iconSize));
230 if(!tooltipList[i].isEmpty()){
231 int index = idL.indexOf(idList[i]);
232 icL[index]->setToolTip(tooltipList[i]);
233 }
234 }
235 }
236 }
237 if(item==-1){item = 0;} //There is now an item to be selected
238 updateIconViewer();
239 checkButtons();
240 }
241
removeItem(QString id)242 void FancySwitcher::removeItem(QString id){
243 int index = idL.indexOf(id.toLower());
244 if(index == -1){
245 qDebug() << "FancySwitcher: Item does not exist -" <<id;
246 return;
247 }else{
248 idL.removeAt(index);
249 icL.removeAt(index);
250 }
251 updateIconViewer();
252 checkButtons();
253 }
254
removeItems(QStringList idList)255 void FancySwitcher::removeItems(QStringList idList){
256 for(int i=0; i<idList.length(); i++){
257 int index = idL.indexOf(idList[i].toLower());
258 if(index == -1){
259 qDebug() << "FancySwitcher: Item does not exist -" <<idList[i];
260 return;
261 }else{
262 idL.removeAt(index);
263 icL.removeAt(index);
264 }
265 }
266 updateIconViewer();
267 checkButtons();
268 }
269
removeAllItems()270 void FancySwitcher::removeAllItems(){
271 if( idL.isEmpty() ){ return; } //do nothing if nothing to change
272 //clear the internal lists
273 idL.clear();
274 icL.clear();
275 item = -1;
276 //now refresh the display
277 updateIconViewer();
278 checkButtons();
279 }
280
currentItem()281 QString FancySwitcher::currentItem(){
282 QString id = idL[item];
283 return id;
284 }
285
setCurrentItem(QString id)286 void FancySwitcher::setCurrentItem(QString id){
287 int index = idL.indexOf(id);
288 if(index == -1){
289 qDebug() << "FancySwitcher: Item does not exist -" << id;
290 return;
291 }else{
292 item = index;
293 displayCurrentItem(false); //do not show animation
294 checkButtons();
295 }
296 }
297
setNumberAnimationFrames(QString numframes)298 void FancySwitcher::setNumberAnimationFrames(QString numframes){
299 if(numframes.toLower()=="smooth"){frames=-1; return;} //auto-detect max
300 if(numframes.toLower()=="instant"){frames=0; return;} //don't use animation
301 bool ok;
302 int num = numframes.toInt(&ok);
303 if(!ok){qDebug() << "FancySwitcher: invalid input for number of animation frames. Must be \"smooth\", \"instant\", or an integer > 0."; return; }
304 if(num < 2){ frames=0; } //1 frame = instant
305 else{ frames=num; } //don't worry about huge numbers, min pixel animation will always be 1 at a time
306
307 }
308
setIconSize(int xysize)309 void FancySwitcher::setIconSize(int xysize){
310 iconSize = xysize; //change the saved icon size
311 //Update the pushbuttons icons
312 pushBack->setIconSize(QSize(iconSize/2,iconSize/2));
313 pushForward->setIconSize(QSize(iconSize/2,iconSize/2));
314 //Update the iconViewer sizes
315 if(isHorizontal){
316 iconViewer->setFixedSize(2.5*iconSize,iconSize+2);
317 }else{
318 iconViewer->setFixedSize(iconSize+2,2.5*iconSize);
319 }
320 updateIconViewer();
321 }
322
changeButtonIcon(QString button,QString iconFile)323 void FancySwitcher::changeButtonIcon(QString button, QString iconFile){
324 if(!QFile::exists(iconFile)){ qDebug() << "FancySwitcher: invalid image file"<<iconFile; return; }
325 if(button.toLower() == "back"){ pushBack->setIcon(QIcon(iconFile)); }
326 else if(button.toLower() == "forward"){ pushForward->setIcon(QIcon(iconFile)); }
327 else{
328 qDebug() << "FancySwitcher: Cannot change the icon for button" << button << " - valid buttons are \"forward\" and \"back\"";
329 }
330 }
331
setStyleSheet(QString style)332 void FancySwitcher::setStyleSheet(QString style){
333 //Propagate the style sheet to both the buttons and the iconViewer
334 pushForward->setStyleSheet(style);
335 pushBack->setStyleSheet(style);
336 iconViewer->setStyleSheet("QGraphicsView { "+style+" } "); //make sure the tooltips are not affected
337 textLabel->setStyleSheet(style);
338 }
339
340