1 /*
2     KBlackBox - A simple game inspired by an emacs module
3 
4     SPDX-FileCopyrightText: 1999-2000 Robert Cimrman <cimrman3@students.zcu.cz>
5     SPDX-FileCopyrightText: 2007 Nicolas Roffet <nicolas-kde@roffet.com>
6 
7     SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 
10 #include "kbbscalablegraphicwidget.h"
11 
12 
13 
14 #include <QAction>
15 #include <QFont>
16 #include <QGraphicsScene>
17 #include <QLCDNumber>
18 #include <QResizeEvent>
19 
20 
21 #include <KGamePopupItem>
22 #include <QIcon>
23 #include <KLocalizedString>
24 #include <QPushButton>
25 
26 
27 #include "kbbballsonboard.h"
28 #include "kbbgamedoc.h"
29 #include "kbbgraphicsitemball.h"
30 #include "kbbgraphicsitemballrepository.h"
31 #include "kbbgraphicsitemblackbox.h"
32 #include "kbbgraphicsitemcursor.h"
33 #include "kbbgraphicsitemlaser.h"
34 #include "kbbgraphicsitemonbox.h"
35 #include "kbbgraphicsitemray.h"
36 #include "kbbgraphicsitemrayresult.h"
37 #include "kbbgraphicsitemset.h"
38 #include "kbbthememanager.h"
39 
40 
41 
42 //
43 // Constructor / Destructor
44 //
45 
KBBScalableGraphicWidget(KBBGameDoc * gameDoc,KBBThemeManager * themeManager,QAction * done)46 KBBScalableGraphicWidget::KBBScalableGraphicWidget(KBBGameDoc* gameDoc, KBBThemeManager* themeManager, QAction* done)
47 {
48 	m_gameDoc = gameDoc;
49 	m_themeManager = themeManager;
50 	m_columns = -2;
51 	m_rows = -2;
52 	m_pause = false;
53 	m_ballNumber = 0;
54 	m_doneAction = done;
55 	m_cursorFollowsMouse = false;
56 
57 	setFrameStyle(QFrame::NoFrame);
58 	setCacheMode(QGraphicsView::CacheBackground);
59 	setMinimumSize(QSize(MINIMUM_SIZE, MINIMUM_SIZE));
60 
61 
62 	m_scene = new QGraphicsScene( 0, 0, 2*BORDER_SIZE, 2*BORDER_SIZE, this );
63 
64 	m_blackbox = new KBBGraphicsItemBlackBox(this, m_scene, m_themeManager, false);
65 	m_blackbox->setKBBScalableGraphicWidget(this);
66 	m_balls = new KBBGraphicsItemSet(m_scene);
67 	m_cursor = new KBBGraphicsItemCursor(this, m_themeManager);
68 	connect(m_cursor, &KBBGraphicsItemCursor::cursorAtNewPosition, this, &KBBScalableGraphicWidget::cursorAtNewPosition);
69 	m_markersNothing = new KBBGraphicsItemSet(m_scene);
70 	m_ballsSolution = new KBBGraphicsItemSet(m_scene);
71 	m_ballsUnsure = new KBBGraphicsItemSet(m_scene);
72 	m_lasers = new KBBGraphicsItemSet(m_scene);
73 	m_rayResults = new KBBGraphicsItemSet(m_scene);
74 
75 	m_playerRay = new KBBGraphicsItemRay(playerRay, m_scene, m_themeManager);
76 	m_solutionRay = new KBBGraphicsItemRay(solutionRay, m_scene, m_themeManager);
77 
78 	// Information message about the score
79 	m_infoScore = new KGamePopupItem();
80 	m_infoScore->setMessageIcon(QPixmap()); // No icon, because they are no scalable.
81 	m_scene->addItem(m_infoScore); // it hides itself by default
82 
83 	m_ballRepository = new KBBGraphicsItemBallRepository(this, themeManager);
84 
85 	setScene(m_scene);
86 
87 	m_doneButton = new QPushButton(m_doneAction->text(), this);
88 	m_doneButton->setIcon(QIcon(m_doneAction->icon()));
89 	m_doneButton->setWhatsThis(m_doneAction->whatsThis());
90 	connect(m_doneButton, &QPushButton::clicked, m_doneAction, &QAction::trigger);
91 	QFont font;
92 	font.setPointSize(m_doneButton->font().pointSize()+2);
93 	font.setBold(true);
94 	m_doneButton->setFont(font);
95 
96 	m_score = new QLCDNumber(3, this);
97 	m_score->setFrameStyle(QFrame::NoFrame);
98 	m_score->setMaximumWidth(m_doneButton->width());
99 	m_score->setFixedHeight((int)(1.5*m_doneButton->height()));
100 	m_score->setToolTip(i18n("Score"));
101 	m_score->setWhatsThis(i18n("<qt><p>This is <b>your score</b>. You should try to get the lowest possible.</p><p>The score increases:<ul><li>with time: <b>1 point</b> per second.</li><li>with the use of lasers:<ul><li><b>3 points</b> if the laser beam hits a ball or exits at the entry point,</li><li><b>9 points</b> if it exits at another entry point.</li></ul></li></ul></p><p>Your score is set to <b>999</b> at the end of the game if you make a mistake.</p></qt>"));
102 
103 	// TODO: not displayed... :(
104 	setWhatsThis(i18n("<qt><p>This is the <b>main game area</b>.</p><ul><li>The <b>black box</b> is in the center.</li><li>On the left, there are the <b>balls</b> you have to place over the black box.</li><li>Around the black box, there are <b>lasers</b> that are replaced with <b>interaction information</b> if you use them.</li></ul></qt>"));
105 	connect(m_blackbox, &KBBGraphicsItemBlackBox::hoverMoved, this, &KBBScalableGraphicWidget::hoverMovePosition);
106 
107 }
108 
109 
~KBBScalableGraphicWidget()110 KBBScalableGraphicWidget::~KBBScalableGraphicWidget()
111 {
112 	delete m_balls;
113 	delete m_markersNothing;
114 	delete m_ballsSolution;
115 	delete m_ballsUnsure;
116 	delete m_lasers;
117 	delete m_rayResults;
118 
119 	delete m_ballRepository;
120 
121 	delete m_scene;
122 }
123 
124 
125 
126 //
127 // Public
128 //
129 
addBall(int boxPosition)130 void KBBScalableGraphicWidget::addBall(int boxPosition)
131 {
132 	addBall(boxPosition, KBBGraphicsItemOnBox::NO_POSITION);
133 }
134 
135 
addBall(int boxPosition,int outsidePosition)136 void KBBScalableGraphicWidget::addBall(int boxPosition, int outsidePosition)
137 {
138 	if (!m_pause && m_inputAccepted && (!m_balls->containsVisible(boxPosition))&& (!m_ballsUnsure->containsVisible(boxPosition))) {
139 		m_boardBallsPlaced->add(boxPosition);
140 		m_balls->insert(new KBBGraphicsItemBall(playerBall, this, m_themeManager, boxPosition, m_columns, m_rows));
141 		m_markersNothing->remove(boxPosition);
142 		if (outsidePosition==KBBGraphicsItemOnBox::NO_POSITION) {
143 			outsidePosition = m_ballRepository->ballToTake();
144 		}
145 		if (outsidePosition!=KBBGraphicsItemSet::NO_INDEX)
146 			m_ballRepository->removeBall(outsidePosition);
147 
148 		updateDoneButton();
149 	}
150 }
151 
152 
addBallUnsure(const int boxPosition)153 void KBBScalableGraphicWidget::addBallUnsure(const int boxPosition)
154 {
155 	addBall(boxPosition);
156 	setBallUnsure(boxPosition, true);
157 }
158 
159 
addMarkerNothing(const int boxPosition)160 void KBBScalableGraphicWidget::addMarkerNothing(const int boxPosition)
161 {
162 	if (!m_pause && m_inputAccepted && (!m_markersNothing->containsVisible(boxPosition))) {
163 		m_markersNothing->insert(new KBBGraphicsItemOnBox(markerNothing, this, m_themeManager, boxPosition, m_columns, m_rows));
164 		m_balls->remove(boxPosition);
165 		m_ballsUnsure->remove(boxPosition);
166 		m_boardBallsPlaced->remove(boxPosition);
167 	}
168 }
169 
170 
drawRay(const int borderPosition)171 void KBBScalableGraphicWidget::drawRay(const int borderPosition)
172 {
173 	if (!m_pause) {
174 		if (!m_inputAccepted) {
175 			m_solutionRay->draw(m_boardBalls, borderPosition);
176 		}
177 		m_playerRay->draw(m_boardBallsPlaced, borderPosition);
178 	}
179 }
180 
181 
mouseBorderClick(const int borderPosition)182 void KBBScalableGraphicWidget::mouseBorderClick(const int borderPosition)
183 {
184 	useLaser(borderPosition);
185 	m_cursor->setBorderPosition(borderPosition);
186 	m_cursor->hide();
187 }
188 
189 
mouseBoxClick(const Qt::MouseButton button,int boxPosition)190 void KBBScalableGraphicWidget::mouseBoxClick(const Qt::MouseButton button, int boxPosition)
191 {
192 	m_cursor->setBoxPosition(boxPosition);
193 	if (button==Qt::RightButton)
194 		switchMarker();
195 	else
196 		switchBall();
197 	m_cursor->hide();
198 }
199 
200 
moveBall(const int boxPositionFrom,const int boxPositionTo)201 int KBBScalableGraphicWidget::moveBall(const int boxPositionFrom, const int boxPositionTo)
202 {
203 	int newPos = positionAfterMovingBall(boxPositionFrom, boxPositionTo);
204 
205 	if (!m_pause && m_inputAccepted && (!m_balls->containsVisible(boxPositionTo)) && (!m_ballsUnsure->containsVisible(boxPositionTo))) {
206 		m_markersNothing->remove(boxPositionTo);
207 		if (boxPositionFrom>=m_columns*m_rows) {
208 			// ball moved from outside of the board
209 			addBall(boxPositionTo, boxPositionFrom);
210 		} else {
211 			// ball moved from a board position
212 			m_boardBallsPlaced->remove(boxPositionFrom);
213 			m_boardBallsPlaced->add(boxPositionTo);
214 		}
215 	}
216 
217 	return newPos;
218 }
219 
220 
moveMarkerNothing(const int boxPositionFrom,const int boxPositionTo)221 int KBBScalableGraphicWidget::moveMarkerNothing(const int boxPositionFrom, const int boxPositionTo)
222 {
223 	if (!m_pause && m_inputAccepted && (!m_markersNothing->containsVisible(boxPositionTo))) {
224 		removeBall(boxPositionTo);
225 		return boxPositionTo;
226 	} else
227 		return boxPositionFrom;
228 }
229 
230 
newGame(int columns,int rows,int ballNumber)231 void KBBScalableGraphicWidget::newGame(int columns, int rows, int ballNumber)
232 {
233 	m_rayNumber = 0;
234 	m_boardBallsPlaced = m_gameDoc->m_ballsPlaced;
235 	setPause(false);
236 	m_ballNumber = ballNumber;
237 
238 	// remove old ray results, all placed balls, all markers "nothing" and all solutions
239 	m_rayResults->clear();
240 	m_balls->clear();
241 	m_ballsUnsure->clear();
242 	m_markersNothing->clear();
243 	m_ballsSolution->clear();
244 
245 	// Reorganize lasers
246 	if ((columns!=m_columns) || (rows!=m_rows)) {
247 		// not the same amount of lasers: We can destroy them and create some new ones
248 		m_lasers->clear();
249 		for (int i=0; i<2*(columns + rows); i++)
250 			m_lasers->insert(new KBBGraphicsItemLaser(this, m_themeManager, i, columns, rows));
251 	} else {
252 		// same amount of lasers: We "recycle" them. (Just destroying them and re-creating them is not working fine: some lasers remain hidden until the next resize... Strange bug with QGraphicsView...)
253 		for (int i=0; i<2*(m_columns + m_rows); i++)
254 			m_lasers->setVisible(i, true);
255 	}
256 
257 	m_ballRepository->newGame(columns, rows, ballNumber);
258 
259 	// set the new size if needed
260 	if (m_columns!=columns || m_rows!=rows) {
261 		m_columns = columns;
262 		m_rows = rows;
263 		m_blackbox->setSize(m_columns, m_rows);
264 		m_cursor->setBoardSize(m_columns, m_rows);
265 		m_scene->setSceneRect(m_ballRepository->x() - RATIO, 0, m_columns*RATIO + 2*BORDER_SIZE - m_ballRepository->x() + RATIO, m_rows*RATIO + 2*BORDER_SIZE);
266 	}
267 	resizeEvent(nullptr);
268 	setInputAccepted(true);
269 }
270 
271 
popupText(const QString & text,int time)272 void KBBScalableGraphicWidget::popupText(const QString& text, int time)
273 {
274 	if (text.isEmpty())
275 		m_infoScore->forceHide();
276 	else {
277 		m_infoScore->setMessageTimeout(time);
278 		m_infoScore->showMessage(text, KGamePopupItem::TopLeft, KGamePopupItem::ReplacePrevious);
279 	}
280 }
281 
282 
positionAfterMovingBall(const int boxPositionFrom,const int boxPositionTo) const283 int KBBScalableGraphicWidget::positionAfterMovingBall(const int boxPositionFrom, const int boxPositionTo) const
284 {
285 	if (!m_pause && m_inputAccepted && (!m_balls->containsVisible(boxPositionTo)) && (!m_ballsUnsure->containsVisible(boxPositionTo))) {
286 		return boxPositionTo;
287 	} else
288 		return boxPositionFrom;
289 }
290 
291 
setPause(bool state)292 void KBBScalableGraphicWidget::setPause(bool state)
293 {
294 	m_pause = state;
295 	for (int i=0;i<2*(m_rows+m_columns);i++) {
296 		if (m_rayResults->containsVisible(i))
297 			m_rayResults->item(i)->setPause(state);
298 	}
299 
300 	updateDoneButton();
301 }
302 
303 
resizeEvent(QResizeEvent *)304 void KBBScalableGraphicWidget::resizeEvent( QResizeEvent* )
305 {
306 	// 1. Compute the size of m_rectBackground
307 	const qreal sW = m_scene->width();
308 	const qreal sH = m_scene->height();
309 	const qreal wW = width();
310 	const qreal wH = height();
311 	const qreal offset = (sH+sW)/100 ;
312 	if (sH*wW > sW*wH) {
313 		// The widget is larger than the scene
314 		qreal w =  wW*sH/wH;
315 		m_rectBackground.setRect((sW-w)/2-offset+m_ballRepository->x()-RATIO, -offset, w + 2*offset, sH + 2*offset);
316 	} else {
317 		// The scene is larger than the widget (or as large)
318 		qreal h =  wH*sW/wW;
319 		m_rectBackground.setRect(-offset+m_ballRepository->x()-RATIO, (sH-h)/2-offset, sW + 2*offset, h + 2*offset);
320 	}
321 
322 	// 2. Resize the scene to fit in the widget
323 	fitInView(m_ballRepository->x()-RATIO, 0, m_columns*RATIO + 2*BORDER_SIZE - m_ballRepository->x() + RATIO, m_rows*RATIO + 2*BORDER_SIZE, Qt::KeepAspectRatio);
324 
325 
326 	m_doneButton->move(OFFSET_DONE_BUTTON, height() - m_doneButton->height() - OFFSET_DONE_BUTTON);
327 	m_score->move(OFFSET_DONE_BUTTON, height() - m_score->height() - m_doneButton->height() - 3*OFFSET_DONE_BUTTON);
328 }
329 
330 
removeAllBalls()331 void KBBScalableGraphicWidget::removeAllBalls()
332 {
333 	for (int i=0;i<m_columns*m_rows;i++) {
334 		removeBall(i);
335 	}
336 }
337 
338 
removeBall(const int boxPosition)339 void KBBScalableGraphicWidget::removeBall(const int boxPosition)
340 {
341 	if (!m_pause && m_inputAccepted) {
342 		m_balls->remove(boxPosition);
343 		m_ballsUnsure->remove(boxPosition);
344 		m_boardBallsPlaced->remove(boxPosition);
345 		m_ballRepository->fillBallsOutside(m_gameDoc->m_ballsPlaced->count());
346 
347 		updateDoneButton();
348 	}
349 }
350 
351 
removeRay()352 void KBBScalableGraphicWidget::removeRay()
353 {
354 	m_playerRay->hide();
355 	m_solutionRay->hide();
356 }
357 
358 
scene()359 QGraphicsScene* KBBScalableGraphicWidget::scene()
360 {
361 	return m_scene;
362 }
363 
364 
setScore(int score)365 void KBBScalableGraphicWidget::setScore(int score)
366 {
367 	m_score->display(score);
368 }
369 
370 
solve(const bool continueGame)371 void KBBScalableGraphicWidget::solve(const bool continueGame)
372 {
373 	m_boardBalls = m_gameDoc->m_balls;
374 
375 	setInputAccepted(continueGame);
376 	if (!continueGame)
377 		setPause(false);
378 
379 	for (int i=0; i<(m_columns * m_rows); i++) {
380 		if ((m_balls->containsVisible(i) || m_ballsUnsure->containsVisible(i)) && m_boardBalls->contains(i)) {
381 			m_ballsSolution->remove(i); // For the sandbox mode: a solution ball could already be here.
382 			m_ballsSolution->insert(new KBBGraphicsItemBall(rightPlayerBall, this, m_themeManager, i, m_columns, m_rows));
383 		}
384 		if ((m_balls->containsVisible(i) || m_ballsUnsure->containsVisible(i)) && !m_boardBalls->contains(i))
385 			m_ballsSolution->insert(new KBBGraphicsItemOnBox(wrongPlayerBall, this, m_themeManager, i, m_columns, m_rows));
386 		if (!m_balls->containsVisible(i) && !m_ballsUnsure->containsVisible(i) && m_boardBalls->contains(i))
387 			m_ballsSolution->insert(new KBBGraphicsItemBall(solutionBall, this, m_themeManager, i, m_columns, m_rows));
388 	}
389 }
390 
391 
392 
393 //
394 // Public slots
395 //
396 
cursorAtNewPosition(int borderPosition)397 void KBBScalableGraphicWidget::cursorAtNewPosition(int borderPosition)
398 {
399 	removeRay();
400 	if ((borderPosition!=KBBGraphicsItemCursor::NO_POSITION) && m_cursor->isVisible())
401 		drawRay(borderPosition);
402 
403 	// highlight
404 	for (int i=0;i<2*(m_rows+m_columns);i++) {
405 		if (m_rayResults->containsVisible(i))
406 			m_rayResults->item(i)->highlight(false);
407 	}
408 	if (m_rayResults->containsVisible(borderPosition))
409 		m_rayResults->item(borderPosition)->highlightBoth(true);
410 
411 }
412 
413 
keyboardEnter()414 void KBBScalableGraphicWidget::keyboardEnter()
415 {
416 	if (m_cursor->isVisible()) {
417 		if (m_cursor->borderPosition() != KBBGraphicsItemCursor::NO_POSITION)
418 			useLaser(m_cursor->borderPosition());
419 		else
420 			switchBall();
421 	}
422 	m_cursor->show();
423 }
424 
425 
keyboardMoveDown()426 void KBBScalableGraphicWidget::keyboardMoveDown()
427 {
428 	if (m_cursor->isVisible())
429 		m_cursor->moveDown();
430 	m_cursor->show();
431 }
432 
433 
keyboardMoveLeft()434 void KBBScalableGraphicWidget::keyboardMoveLeft()
435 {
436 	if (m_cursor->isVisible())
437 		m_cursor->moveLeft();
438 	m_cursor->show();
439 }
440 
441 
keyboardMoveRight()442 void KBBScalableGraphicWidget::keyboardMoveRight()
443 {
444 	if (m_cursor->isVisible())
445 		m_cursor->moveRight();
446 	m_cursor->show();
447 }
448 
449 
keyboardMoveUp()450 void KBBScalableGraphicWidget::keyboardMoveUp()
451 {
452 	if (m_cursor->isVisible())
453 		m_cursor->moveUp();
454 	m_cursor->show();
455 }
456 
457 
keyboardSpace()458 void KBBScalableGraphicWidget::keyboardSpace()
459 {
460 	if (m_cursor->isVisible()) {
461 		if (m_cursor->boxPosition() != KBBGraphicsItemCursor::NO_POSITION)
462 			switchMarker();
463 	}
464 	m_cursor->show();
465 }
466 
467 
468 
469 //
470 // Protected
471 //
472 
drawBackground(QPainter * painter,const QRectF &)473 void KBBScalableGraphicWidget::drawBackground(QPainter* painter, const QRectF&)
474 {
475 	m_themeManager->svgRenderer()->render(painter, m_themeManager->elementId(background), m_rectBackground);
476 }
477 
478 
479 
480 //
481 // Private
482 //
483 
removeMarkerNothing(const int boxPosition)484 void KBBScalableGraphicWidget::removeMarkerNothing(const int boxPosition)
485 {
486 	if (!m_pause && m_inputAccepted) {
487 		m_markersNothing->remove(boxPosition);
488 	}
489 }
490 
491 
setBallUnsure(const int boxPosition,const bool unsure)492 void KBBScalableGraphicWidget::setBallUnsure(const int boxPosition, const bool unsure)
493 {
494 	if (!m_pause && m_inputAccepted) {
495 		if (unsure) {
496 			m_balls->remove(boxPosition);
497 			m_ballsUnsure->insert(new KBBGraphicsItemBall(unsureBall, this, m_themeManager, boxPosition, m_columns, m_rows));
498 		} else {
499 			m_ballsUnsure->remove(boxPosition);
500 			m_balls->insert(new KBBGraphicsItemBall(playerBall, this, m_themeManager, boxPosition, m_columns, m_rows));
501 		}
502 	}
503 }
504 
505 
setInputAccepted(bool inputAccepted)506 void KBBScalableGraphicWidget::setInputAccepted(bool inputAccepted)
507 {
508 	m_inputAccepted = inputAccepted;
509 	if (m_inputAccepted) {
510 		setFocusPolicy( Qt::StrongFocus );
511 		setFocus();
512 	} else {
513 		setFocusPolicy( Qt::NoFocus );
514 		clearFocus();
515 	}
516 
517 	updateDoneButton();
518 }
519 
520 
switchBall()521 void KBBScalableGraphicWidget::switchBall()
522 {
523 	if ((m_balls->containsVisible(m_cursor->boxPosition())) || (m_ballsUnsure->containsVisible(m_cursor->boxPosition())))
524 		removeBall(m_cursor->boxPosition());
525 	else if (m_ballRepository->ballToTake() != KBBGraphicsItemSet::NO_INDEX)
526 		addBall(m_cursor->boxPosition());
527 }
528 
529 
switchMarker()530 void KBBScalableGraphicWidget::switchMarker()
531 {
532 	if (m_balls->containsVisible(m_cursor->boxPosition()))
533 		setBallUnsure(m_cursor->boxPosition(), true);
534 	else if (m_markersNothing->containsVisible(m_cursor->boxPosition()))
535 		removeMarkerNothing(m_cursor->boxPosition());
536         else{
537 		removeBall(m_cursor->boxPosition());
538 		addMarkerNothing(m_cursor->boxPosition());
539         }
540 }
541 
542 
updateDoneButton()543 void KBBScalableGraphicWidget::updateDoneButton()
544 {
545 	m_doneButton->setEnabled(m_doneAction->isEnabled());
546 	m_doneButton->setToolTip(m_doneAction->toolTip());
547 }
548 
549 
useLaser(const int incomingPosition)550 void KBBScalableGraphicWidget::useLaser(const int incomingPosition)
551 {
552 	if (!m_pause && m_gameDoc->mayShootRay(incomingPosition) && m_inputAccepted && m_lasers->containsVisible(incomingPosition)) {
553 		const int outgoingPosition = m_gameDoc->shootRay(incomingPosition);
554 
555 		KBBGraphicsItemRayResult* inRay;
556 		KBBGraphicsItemRayResult* outRay;
557 
558 		int rayNumberOrReflection = 0;
559 		if (outgoingPosition==KBBGameDoc::HIT_POSITION)
560 			rayNumberOrReflection = KBBGameDoc::HIT_POSITION;
561 		if ((outgoingPosition!=incomingPosition) && (outgoingPosition!=KBBGameDoc::HIT_POSITION)) {
562 			m_rayNumber++;
563 			m_lasers->setVisible(outgoingPosition, false);
564 			m_rayResults->insert(outRay = new KBBGraphicsItemRayResult(this, m_themeManager, m_scene, outgoingPosition, m_columns, m_rows, m_rayNumber));
565 			rayNumberOrReflection = m_rayNumber;
566 		}
567 		m_rayResults->insert(inRay = new KBBGraphicsItemRayResult(this, m_themeManager, m_scene, incomingPosition, m_columns, m_rows, rayNumberOrReflection));
568 
569 		if ((outgoingPosition!=incomingPosition) && (outgoingPosition!=KBBGameDoc::HIT_POSITION)) {
570 			inRay->setOpposite(outRay);
571 			outRay->setOpposite(inRay);
572 		}
573 
574 		m_scene->update();
575 		m_lasers->setVisible(incomingPosition, false);
576 
577         popupText(QString()); // To Remove any displayed text quicker.
578 
579 		cursorAtNewPosition(incomingPosition);
580 	}
581 }
582 
hoverMovePosition(int pos)583 void KBBScalableGraphicWidget::hoverMovePosition(int pos)
584 {
585 	if (m_cursorFollowsMouse)
586 	{
587 		m_cursor->show();
588 		m_cursor->setBoxPosition(pos);
589 		m_cursor->updatePositions();
590 	}
591 }
592 
toggleCursor()593 void KBBScalableGraphicWidget::toggleCursor()
594 {
595 	m_cursorFollowsMouse = !m_cursorFollowsMouse;
596 	if (m_cursorFollowsMouse == false){
597 		m_cursor->hide();
598 	}
599 }
600 
cursorOff()601 void KBBScalableGraphicWidget::cursorOff() {
602 	m_cursor->hide();
603 }
604 
605