Hello community,
here is the log from the commit of package ksudoku for openSUSE:Factory checked in at 2016-01-07 00:22:45
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ksudoku (Old)
and /work/SRC/openSUSE:Factory/.ksudoku.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ksudoku"
Changes:
--------
--- /work/SRC/openSUSE:Factory/ksudoku/ksudoku.changes 2015-11-15 12:40:07.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.ksudoku.new/ksudoku.changes 2016-01-07 00:22:46.000000000 +0100
@@ -1,0 +2,9 @@
+Sun Dec 13 13:27:32 UTC 2015 - tittiatcoke@gmail.com
+
+- Update to KDE Applications 15.12.0
+ * KDE Applications 15.12.0
+ * https://www.kde.org/announcements/announce-applications-15.12.0.php
+ * boo#958887
+
+
+-------------------------------------------------------------------
Old:
----
ksudoku-15.08.3.tar.xz
New:
----
ksudoku-15.12.0.tar.xz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ ksudoku.spec ++++++
--- /var/tmp/diff_new_pack.1FgOVk/_old 2016-01-07 00:22:48.000000000 +0100
+++ /var/tmp/diff_new_pack.1FgOVk/_new 2016-01-07 00:22:48.000000000 +0100
@@ -24,7 +24,7 @@
License: GPL-2.0+
Group: Amusements/Games/Board/Puzzle
Url: http://www.kde.org
-Version: 15.08.3
+Version: 15.12.0
Release: 0
Source0: ksudoku-%{version}.tar.xz
BuildRoot: %{_tmppath}/%{name}-%{version}-build
++++++ ksudoku-15.08.3.tar.xz -> ksudoku-15.12.0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksudoku-15.08.3/src/gui/CMakeLists.txt new/ksudoku-15.12.0/src/gui/CMakeLists.txt
--- old/ksudoku-15.08.3/src/gui/CMakeLists.txt 2015-11-04 14:02:01.000000000 +0100
+++ new/ksudoku-15.12.0/src/gui/CMakeLists.txt 2015-11-05 05:20:19.000000000 +0100
@@ -9,6 +9,7 @@
symbols.cpp
gamevariants.cpp
welcomescreen.cpp
+ puzzleprinter.cpp
)
set(ksudoku_views_SRCS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksudoku-15.08.3/src/gui/gamevariants.cpp new/ksudoku-15.12.0/src/gui/gamevariants.cpp
--- old/ksudoku-15.08.3/src/gui/gamevariants.cpp 2015-11-04 14:02:01.000000000 +0100
+++ new/ksudoku-15.12.0/src/gui/gamevariants.cpp 2015-11-05 05:20:19.000000000 +0100
@@ -119,38 +119,65 @@
// class GameVariantDelegate
////////////77/////////////////////////////////////////////////////////////////
-GameVariantDelegate::GameVariantDelegate(QObject* parent)
- : QItemDelegate(parent)
+GameVariantDelegate::GameVariantDelegate(QObject* parent, QWidget * viewport)
+ : QItemDelegate(parent),
+ m_viewport(viewport)
{
}
-QSize GameVariantDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const {
- Q_UNUSED(option);
+QSize GameVariantDelegate::sizeHint(const QStyleOptionViewItem& option,
+ const QModelIndex& index) const
+{
Q_UNUSED(index);
- QSize size(m_leftMargin+m_iconWidth+m_rightMargin+m_separatorPixels*2, 0);
- if( m_iconHeight < option.fontMetrics.height()*3 )
- size.setHeight( option.fontMetrics.height()*3 + m_separatorPixels*3);
- else
- size.setHeight( m_iconHeight+m_separatorPixels*2);
+ // Fit a varying number of columns into the list-view.
+ int viewportWidth = m_viewport->width();
+ int hintWidth = m_minWidth;
+ int nItemsPerRow = viewportWidth / m_minWidth;
+
+ // Expand the hinted width, so that the columns will fill the viewport.
+ if (nItemsPerRow > 0) {
+ int adjustment = (viewportWidth % nItemsPerRow) ? 0 : 1;
+ // The adjustment works around a graphics glitch, when nItemsPerRow
+ // exactly divides viewportWidth and instead of nItemsPerRow columns
+ // we suddenly get one column less, plus a large empty space, even
+ // though QListView::spacing() is zero.
+ hintWidth = (viewportWidth - adjustment) / nItemsPerRow;
+ }
+ // Set the height to contain the icon or 4 lines of text.
+ QSize size (hintWidth, 0);
+ int fontHeight = option.fontMetrics.height();
+ if (m_iconHeight < fontHeight*4) {
+ size.setHeight (fontHeight*4 + m_separatorPixels*3);
+ }
+ else {
+ size.setHeight (m_iconHeight + m_separatorPixels*2);
+ }
return size;
}
void GameVariantDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
- // show background
QColor bkgColor;
+
+ // Calculate item's column num in list-view. Add 1 in odd-numbered rows.
+ int nItemsPerRow = qMax (m_viewport->width() / option.rect.width(), 1);
+ int oddColumn = index.row() % nItemsPerRow;
+ oddColumn = oddColumn + ((index.row() / nItemsPerRow) % 2);
+
if (option.state & QStyle::State_Selected) {
bkgColor = option.palette.color(QPalette::Highlight);
- painter->fillRect(option.rect, bkgColor);
- } else if(index.row() % 2) {
+ } else if (oddColumn % 2) {
+ // The shading alternates along each row in the list view and
+ // each odd-numbered row starts with a shaded item, so we have
+ // a checkerboard pattern, regardless of whether nItemsPerRow
+ // is odd or even (see the above calculation).
bkgColor = option.palette.color(QPalette::AlternateBase);
- painter->fillRect(option.rect, bkgColor);
} else {
bkgColor = option.palette.color(QPalette::Base);
- painter->fillRect(option.rect, bkgColor);
}
+ painter->fillRect(option.rect, bkgColor);
QRect contentRect = option.rect.adjusted(m_leftMargin, m_separatorPixels, -m_rightMargin, -m_separatorPixels);
@@ -190,8 +217,10 @@
painter->setFont(previousFont);
// Show Description
- QString descrStr = painter->fontMetrics().elidedText(description(index), Qt::ElideRight, contentRect.width());
- painter->drawText(contentRect, descrStr);
+ QTextOption wrap(Qt::AlignLeft);
+ wrap.setWrapMode(QTextOption::WordWrap);
+ QString descrStr = description(index);
+ painter->drawText(contentRect, descrStr, wrap);
painter->setPen(previousPen);
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksudoku-15.08.3/src/gui/gamevariants.h new/ksudoku-15.12.0/src/gui/gamevariants.h
--- old/ksudoku-15.08.3/src/gui/gamevariants.h 2015-11-04 14:02:01.000000000 +0100
+++ new/ksudoku-15.12.0/src/gui/gamevariants.h 2015-11-05 05:20:19.000000000 +0100
@@ -102,7 +102,7 @@
};
public:
- GameVariantDelegate(QObject* parent = 0);
+ GameVariantDelegate(QObject* parent = 0, QWidget * viewport = 0);
public:
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const;
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
@@ -116,11 +116,15 @@
QString icon(const QModelIndex& index) const;
bool configurable(const QModelIndex& index) const;
private:
+ QWidget * m_viewport;
+
static const int m_iconWidth = 48;
static const int m_iconHeight = 48;
static const int m_leftMargin = 16;
static const int m_rightMargin = 12;
static const int m_separatorPixels = 8;
+ static const int m_minWidth = m_leftMargin + m_rightMargin +
+ 4 * (m_iconWidth + m_separatorPixels*2);
};
class SudokuGame : public GameVariant {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksudoku-15.08.3/src/gui/ksudoku.cpp new/ksudoku-15.12.0/src/gui/ksudoku.cpp
--- old/ksudoku-15.08.3/src/gui/ksudoku.cpp 2015-11-04 14:02:01.000000000 +0100
+++ new/ksudoku-15.12.0/src/gui/ksudoku.cpp 2015-11-05 05:20:19.000000000 +0100
@@ -32,9 +32,6 @@
#include <QLabel>
#include <QComboBox>
-#include <QPrinter>
-#include <QPrintDialog>
-
#include <KLocale>
#include <KActionCollection>
#include <KStandardAction>
@@ -62,6 +59,8 @@
#include "skgraph.h"
#include "serializer.h"
+#include "puzzleprinter.h"
+
#include
#include
#include
@@ -124,9 +123,7 @@
:
KXmlGuiWindow(),
m_gameVariants(new GameVariantCollection(this, true)),
- m_printer(0),
- m_p(0),
- m_quadrant(0)
+ m_puzzlePrinter(0)
{
setObjectName( QLatin1String("ksudoku" ));
@@ -172,8 +169,7 @@
KSudoku::~KSudoku()
{
- delete m_p;
- delete m_printer;
+ delete m_puzzlePrinter;
endCurrentGame();
}
@@ -726,195 +722,17 @@
i18n("There seems to be no puzzle to print."));
return;
}
- SudokuType t = game.puzzle()->graph()->specificType();
- if ((t == Mathdoku) || (t == KillerSudoku)) {
- KMessageBox::information (this,
- i18n("Sorry, printing Mathdoku and Killer Sudoku "
- "puzzles is not yet supported."));
- return;
- }
- sendToPrinter (game.puzzle());
-}
-
-void KSudoku::sendToPrinter (const Puzzle * puzzle)
-{
- const SKGraph * graph = puzzle->graph();
- if (graph->sizeZ() > 1) {
- KMessageBox::information (this,
- i18n("Sorry, cannot print three-dimensional puzzles."));
- return;
- }
- const bool printMulti = Settings::printMulti();
- const int across = 2;
- const int down = 2;
- const QString labels = (graph->base() <= 3) ? "123456789" :
- "ABCDEFGHIJKLMNOPQRSTUVWXY";
- enum Edge {Left = 0, Right, Above, Below, Detached};
- const int All = (1 << Left) + (1 << Right) + (1 << Above) + (1 << Below);
-
- // The printer and painter objects can persist between print requests, so
- // (if required) we can print several puzzles per page and defer printing
- // until the page is full or KSudoku terminates and the painter ends itself.
- // NOTE: Must create painter before using functions like m_printer->width().
- if (m_printer == 0) {
- m_printer = new QPrinter (QPrinter::HighResolution);
- QPrintDialog * dialog = new QPrintDialog(m_printer, this);
- dialog->setWindowTitle(i18n("Print Sudoku Puzzle"));
- if (dialog->exec() != QDialog::Accepted) {
- delete m_printer;
- m_printer = 0;
- return;
- }
- }
- if (m_p == 0) {
- m_p = new QPainter (m_printer); // Start a new print job.
- }
-
- QVector<int> edges (graph->size(), 0);
- int order = graph->order();
-
- for (int n = 0; n < graph->cliqueCount(); n++) {
- // Find out which groups are blocks of cells, not rows or columns.
- QVector<int> clique = graph->clique (n);
- int x = graph->cellPosX (clique.at (0));
- int y = graph->cellPosY (clique.at (0));
- bool isRow = true;
- bool isCol = true;
- for (int k = 1; k < order; k++) {
- if (graph->cellPosX (clique.at (k)) != x) isRow = false;
- if (graph->cellPosY (clique.at (k)) != y) isCol = false;
- }
- if (isRow || isCol) continue; // Skip rows and columns.
-
- // Mark the outside edges of each block.
- for (int k = 0; k < order; k++) {
- int cell = clique.at (k);
- int x = graph->cellPosX (cell);
- int y = graph->cellPosY (cell);
- int nb[4] = {-1, -1, -1, -1};
- int lim = graph->sizeX() - 1;
-
- // Start with all edges: remove them as neighbours are found.
- int edge = All;
- nb[Left] = (x > 0) ? graph->cellIndex (x-1, y) : -1;
- nb[Right] = (x < lim) ? graph->cellIndex (x+1, y) : -1;
- nb[Above] = (y > 0) ? graph->cellIndex (x, y-1) : -1;
- nb[Below] = (y < lim) ? graph->cellIndex (x, y+1) : -1;
- for (int neighbour = 0; neighbour < 4; neighbour++) {
- if ((nb[neighbour] < 0) || (puzzle->value(nb[neighbour]) < 0)) {
- continue; // No neighbour on this side.
- }
- for (int cl = 0; cl < order; cl++) {
- if (clique.at (cl) == nb[neighbour]) {
- edge = edge - (1 << neighbour);
- }
- }
- }
- edge = (edge == All) ? (1 << Detached) : edge;
- edges [cell] |= edge; // Merge the edges found for this cell.
- }
- }
-
- // Calculate the printed dimensions of the puzzle.
- m_printer->setFullPage (false); // Allow minimal margins.
- int pixels = qMin (m_printer->width(), m_printer->height());
- int size = pixels - (pixels / 20); // Allow about 2.5% each side.
- int divs = (graph->sizeX() > 20) ? graph->sizeX() : 20;
- int sCell = size / divs; // Size of each cell.
- size = graph->sizeX() * sCell; // Size of the whole puzzle.
-
- // Check if we require more than one puzzle per page and if they would fit.
- bool manyUp = printMulti && (pixels > (across * size));
- int margin1 = manyUp ? (pixels - across * size) / (across + 1) // > 1.
- : (pixels - size) / 2; // = 1.
- pixels = qMax (m_printer->width(), m_printer->height());
- int margin2 = manyUp ? (pixels - down * size) / (down + 1) // > 1.
- : (pixels - size) / 2; // = 1.
-
- // Check for landscape vs. portrait mode and set the margins accordingly.
- int topX = (m_printer->width() < m_printer->height())? margin1 : margin2;
- int topY = (m_printer->width() < m_printer->height())? margin2 : margin1;
-
- if ((m_quadrant > 0) && (! manyUp)) {
- bool test = m_printer->newPage(); // Page has previous output.
- m_quadrant = 0;
- }
- topX = manyUp ? topX + (m_quadrant % across) * (topX + size) : topX;
- topY = manyUp ? topY + (m_quadrant / across) * (topY + size) : topY;
- m_quadrant = manyUp ? (m_quadrant + 1) : (across * down);
-
- // Set up parameters for the heavy and light line-drawing.
- int thin = sCell / 40; // Allow 2.5%.
- int thick = (thin > 0) ? 3 * thin : 3;
- int nLines = graph->order() + 1;
-
- QPen light (QColor("#888888"));
- QPen heavy (QColor(QString("black")));
- light.setWidth (thin);
- heavy.setWidth (thick);
- heavy.setCapStyle (Qt::RoundCap);
-
- // Set font size 60% height of cell. Do not draw gray lines on top of black.
- QFont f = m_p->font();
- f.setPixelSize ((sCell * 6) / 10);
- m_p->setFont (f);
- m_p->setCompositionMode (QPainter::CompositionMode_Darken);
-
- // Draw each cell in the puzzle.
- for (int n = 0; n < graph->size(); n++) {
- if (puzzle->value (n) < 0) {
- continue; // Do not draw unused cells.
- }
- int x = topX + sCell * graph->cellPosX (n);
- int y = topY + sCell * graph->cellPosY (n);
- QRect rect (x, y, sCell, sCell);
- int edge = edges.at (n);
- if (edge & (1 << Detached)) { // Shade a cell, as in XSudoku.
- m_p->fillRect (rect, QColor ("#DDDDDD"));
- }
- m_p->setPen (light); // First draw every cell light.
- m_p->drawRect (rect);
- m_p->setPen (heavy); // Draw block boundaries heavy.
- if (edge & (1<drawLine (x, y, x, y + sCell);
- if (edge & (1<drawLine (x+sCell, y, x+sCell, y+sCell);
- if (edge & (1<drawLine (x, y, x+sCell, y);
- if (edge & (1<drawLine (x, y+sCell, x+sCell, y+sCell);
-
- // Draw original puzzle values heavy: filled-in/solution values light.
- int v = currentGame().value (n) - 1;
- if (v >= 0) { // Skip empty cells.
- m_p->setPen ((puzzle->value (n) > 0) ? heavy : light);
- m_p->drawText (rect, Qt::AlignCenter, labels.mid (v, 1));
- }
- }
- if ((! manyUp) || (m_quadrant >= (across * down))) {
- endPrint(); // Print immediately.
- }
- else {
- KMessageBox::information (this,
- i18n ("The KSudoku setting for printing several puzzles per page "
- "is currently selected.\n\n"
- "Your puzzle will be printed when no more will fit on the "
- "page or when KSudoku terminates."));
- }
-}
-
-void KSudoku::endPrint()
-{
- if (m_p != 0) {
- // The current print output goes to the printer when the painter ends.
- m_p->end();
- delete m_p;
- m_p = 0;
- m_quadrant = 0;
- KMessageBox::information (this,
- i18n ("KSudoku has sent output to your printer."));
+ if (! m_puzzlePrinter) {
+ m_puzzlePrinter = new PuzzlePrinter (this);
}
+ m_puzzlePrinter->print (game);
}
bool KSudoku::queryClose()
{
- endPrint();
+ if (m_puzzlePrinter) {
+ m_puzzlePrinter->endPrint();
+ }
return true;
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksudoku-15.08.3/src/gui/ksudoku.h new/ksudoku-15.12.0/src/gui/ksudoku.h
--- old/ksudoku-15.08.3/src/gui/ksudoku.h 2015-11-04 14:02:01.000000000 +0100
+++ new/ksudoku-15.12.0/src/gui/ksudoku.h 2015-11-05 05:20:19.000000000 +0100
@@ -3,6 +3,7 @@
* Copyright 2006-2007 Mick Kappenburg *
* Copyright 2006-2007 Johannes Bergmeier *
* Copyright 2012 Ian Wadham *
+ * Copyright 2015 Ian Wadham *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@@ -44,6 +45,7 @@
}
class SKGraph;
+class PuzzlePrinter;
/**
* This class serves as the main window for ksudoku. It handles the
@@ -151,9 +153,6 @@
void adaptActions2View();
- void sendToPrinter (const ksudoku::Puzzle * puzzle);
- void endPrint();
-
private:
QWidget* wrapper;
@@ -170,9 +169,7 @@
ksudoku::GameActions* m_gameActions;
- QPrinter * m_printer;
- QPainter * m_p;
- int m_quadrant;
+ PuzzlePrinter * m_puzzlePrinter;
};
#endif // _KSUDOKU_H_
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksudoku-15.08.3/src/gui/puzzleprinter.cpp new/ksudoku-15.12.0/src/gui/puzzleprinter.cpp
--- old/ksudoku-15.08.3/src/gui/puzzleprinter.cpp 1970-01-01 01:00:00.000000000 +0100
+++ new/ksudoku-15.12.0/src/gui/puzzleprinter.cpp 2015-11-05 05:20:19.000000000 +0100
@@ -0,0 +1,429 @@
+/***************************************************************************
+ * Copyright 2005-2007 Francesco Rossi *
+ * Copyright 2006-2007 Mick Kappenburg *
+ * Copyright 2006-2008 Johannes Bergmeier *
+ * Copyright 2012 Ian Wadham *
+ * Copyright 2015 Ian Wadham *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "globals.h"
+
+#include <QPrinter>
+#include <QPrintDialog>
+#include <QPainter>
+#include <QLine>
+
+#include <KLocale>
+
+#include "puzzle.h"
+#include "skgraph.h"
+#include "ksudokugame.h"
+#include "puzzleprinter.h"
+
+#include "settings.h"
+
+#include <KMessageBox>
+
+PuzzlePrinter::PuzzlePrinter(QWidget * parent)
+ :
+ QObject(parent),
+ m_parent(parent),
+ m_printer(0),
+ m_p(0),
+ m_quadrant(0),
+ m_across(2),
+ m_down(2)
+{
+}
+
+PuzzlePrinter::~PuzzlePrinter()
+{
+}
+
+void PuzzlePrinter::print (const ksudoku::Game & game)
+{
+ const ksudoku::Puzzle * puzzle = game.puzzle();
+ const SKGraph * graph = puzzle->graph();
+ if (graph->sizeZ() > 1) {
+ KMessageBox::information (m_parent,
+ i18n("Sorry, cannot print three-dimensional puzzles."));
+ return;
+ }
+ const int leastCellsToFit = 20; // Avoids huge cells in small puzzles.
+
+ // Set up a QPrinter and a QPainter and allocate space on the page.
+ bool pageFilled = setupOutputDevices (leastCellsToFit, graph->sizeX());
+ if (! m_printer) {
+ return; // The user did not select a printer.
+ }
+
+ // Draw the puzzle grid and its contents.
+ bool hasBlocks = (graph->specificType() != Mathdoku);
+ bool hasCages = ((graph->specificType() == Mathdoku) ||
+ (graph->specificType() == KillerSudoku));
+ bool killerStyle = (graph->specificType() == KillerSudoku);
+
+ if (hasBlocks) { // Only Mathdoku has no blocks.
+ drawBlocks (puzzle, graph);
+ }
+ if (hasCages) { // Mathdoku and KillerSudoku have cages.
+ drawCages (puzzle, graph, killerStyle); // KillerSudoku has blocks too.
+ }
+ drawValues (game, graph); // Print starting and filled-in values.
+
+ if (pageFilled) {
+ endPrint(); // Print immediately.
+ }
+ else {
+ KMessageBox::information (m_parent,
+ i18n ("The KSudoku setting for printing several puzzles per page "
+ "is currently selected.\n\n"
+ "Your puzzle will be printed when no more will fit on the "
+ "page or when KSudoku terminates."));
+ }
+}
+
+void PuzzlePrinter::endPrint()
+{
+ if (m_p != 0) {
+ // The current print output goes to the printer when the painter ends.
+ m_p->end();
+ delete m_p;
+ m_p = 0;
+ m_quadrant = 0;
+ KMessageBox::information (m_parent,
+ i18n ("KSudoku has sent output to your printer."));
+ }
+}
+
+bool PuzzlePrinter::setupOutputDevices (int leastCellsToFit, int puzzleWidth)
+{
+ // The printer and painter objects can persist between print requests, so
+ // (if required) we can print several puzzles per page and defer printing
+ // until the page is full or KSudoku terminates and the painter ends itself.
+ // NOTE: Must create painter before using functions like m_printer->width().
+ if (m_printer == 0) {
+ m_printer = new QPrinter (QPrinter::HighResolution);
+ QPrintDialog * dialog = new QPrintDialog(m_printer, m_parent);
+ dialog->setWindowTitle(i18n("Print Sudoku Puzzle"));
+ if (dialog->exec() != QDialog::Accepted) {
+ delete m_printer;
+ m_printer = 0;
+ return false;
+ }
+ }
+ if (m_p == 0) {
+ m_p = new QPainter (m_printer); // Start a new print job.
+ }
+ m_printMulti = Settings::printMulti();
+
+ // Calculate the printed dimensions of the puzzle.
+ m_printer->setFullPage (false); // Allow minimal margins.
+ int pixels = qMin (m_printer->width(), m_printer->height());
+ int space = pixels - (pixels / 20); // Allow about 2.5% each side.
+ int pCells = qMax (leastCellsToFit, puzzleWidth); // Cells to allocate.
+ m_sCell = space / pCells; // Size of each cell.
+ int size = puzzleWidth * m_sCell; // Size of the whole puzzle.
+
+ // Check if we require more than one puzzle per page and if they would fit.
+ bool manyUp = m_printMulti && (pixels > (m_across * size));
+ int margin1 = manyUp ? (pixels - m_across * size) / (m_across + 1) // > 1.
+ : (pixels - size) / 2; // = 1.
+ pixels = qMax (m_printer->width(), m_printer->height());
+ int margin2 = manyUp ? (pixels - m_down * size) / (m_down + 1) // > 1.
+ : (pixels - size) / 2; // = 1.
+
+ // Check for landscape vs. portrait mode and set the margins accordingly.
+ m_topX = (m_printer->width() < m_printer->height())? margin1 : margin2;
+ m_topY = (m_printer->width() < m_printer->height())? margin2 : margin1;
+
+ // If new puzzle will not fit a quadrant and page is not empty, flush page.
+ if ((m_quadrant > 0) && (! manyUp)) {
+ m_printer->newPage();
+ m_quadrant = 0;
+ }
+ m_topX = manyUp ? m_topX + (m_quadrant%m_across) * (m_topX + size) : m_topX;
+ m_topY = manyUp ? m_topY + (m_quadrant/m_across) * (m_topY + size) : m_topY;
+ m_quadrant = manyUp ? (m_quadrant + 1) : (m_across * m_down);
+
+ // Set up pen-parameters for the heavy and light line-drawing.
+ int thin = m_sCell / 40; // Allow 2.5%.
+ int thick = (thin > 0) ? 2 * thin : 2;
+
+ m_light.setColor (QColor("#888888"));
+ m_light.setWidth (thin);
+ m_heavy.setColor (QColor(QString("black")));
+ m_heavy.setWidth (thick);
+ m_heavy.setCapStyle (Qt::RoundCap);
+ m_dashes.setColor (QColor(QString("black")));
+ m_dashes.setWidth (thin);
+ m_dashes.setStyle (Qt::DashLine);
+
+ // Return true if the page will be filled up after drawing the puzzle.
+ return ((! manyUp) || (m_quadrant >= (m_across * m_down)));
+}
+
+void PuzzlePrinter::drawBlocks (const ksudoku::Puzzle * puzzle,
+ const SKGraph * graph)
+{
+ QVector<int> edges (graph->size(), 0); // One bitmap per cell.
+ int order = graph->order();
+
+ for (int n = 0; n < graph->cliqueCount(); n++) {
+ // Find out which groups are blocks of cells, not rows or columns.
+ QVector<int> clique = graph->clique (n);
+ int x = graph->cellPosX (clique.at (0));
+ int y = graph->cellPosY (clique.at (0));
+ bool isRow = true;
+ bool isCol = true;
+ for (int k = 1; k < order; k++) {
+ if (graph->cellPosX (clique.at (k)) != x) isRow = false;
+ if (graph->cellPosY (clique.at (k)) != y) isCol = false;
+ }
+ if (isRow || isCol) continue; // Skip rows and columns.
+
+ // Mark the outside edges of each block.
+ markEdges (clique, puzzle, graph, edges);
+ }
+
+ // Draw each cell in the puzzle.
+ for (int n = 0; n < graph->size(); n++) {
+ if (puzzle->value (n) < 0) {
+ continue; // Do not draw unused cells.
+ }
+ drawCell (graph->cellPosX (n), graph->cellPosY (n), edges.at (n));
+ }
+}
+
+void PuzzlePrinter::drawCages (const ksudoku::Puzzle * puzzle,
+ const SKGraph * graph, bool killerStyle)
+{
+ QVector<int> edges (graph->size(), 0); // One bitmap per cell.
+ for (int n = 0; n < graph->cageCount(); n++) {
+ // Mark the outside edges of each cage.
+ markEdges (graph->cage (n), puzzle, graph, edges);
+ }
+ if (killerStyle) {
+ drawKillerSudokuCages (graph, edges);
+ }
+ else {
+ // Draw each cell in the puzzle.
+ for (int n = 0; n < graph->size(); n++) {
+ if (puzzle->value (n) < 0) {
+ continue; // Do not draw unused cells.
+ }
+ drawCell (graph->cellPosX (n), graph->cellPosY (n), edges.at (n));
+ }
+ }
+ for (int n = 0; n < graph->cageCount(); n++) {
+ drawCageLabel (graph, n, killerStyle);
+ }
+}
+
+void PuzzlePrinter::markEdges (const QVector<int> & cells,
+ const ksudoku::Puzzle * puzzle,
+ const SKGraph * graph, QVector<int> & edges)
+{
+ const int All = (1 << Left) + (1 << Right) + (1 << Above) + (1 << Below);
+
+ int nCells = cells.count();
+ for (int k = 0; k < nCells; k++) {
+ int cell = cells.at (k);
+ int x = graph->cellPosX (cell);
+ int y = graph->cellPosY (cell);
+ int nb[4] = {-1, -1, -1, -1};
+ int lim = graph->sizeX() - 1;
+
+ // Start with all edges: remove them as neighbours are found.
+ int edge = All;
+ nb[Left] = (x > 0) ? graph->cellIndex (x-1, y) : -1;
+ nb[Right] = (x < lim) ? graph->cellIndex (x+1, y) : -1;
+ nb[Above] = (y > 0) ? graph->cellIndex (x, y-1) : -1;
+ nb[Below] = (y < lim) ? graph->cellIndex (x, y+1) : -1;
+ for (int neighbour = 0; neighbour < 4; neighbour++) {
+ if ((nb[neighbour] < 0) || (puzzle->value(nb[neighbour]) < 0)) {
+ continue; // No neighbour on this side.
+ }
+ for (int cl = 0; cl < nCells; cl++) {
+ if (cells.at (cl) == nb[neighbour]) {
+ edge = edge - (1 << neighbour);
+ }
+ }
+ }
+ // Check for size-1 cages or detached cells as in XSudoku diagonals.
+ if ((edge == All) && (graph->specificType() != Mathdoku) &&
+ (graph->specificType() != KillerSudoku)) {
+ edge = (1 << Detached);
+ }
+ edges [cell] |= edge; // Merge the edges found for this cell.
+ }
+}
+
+void PuzzlePrinter::drawCell (int posX, int posY, int edge)
+{
+ int x = m_topX + m_sCell * posX;
+ int y = m_topY + m_sCell * posY;
+ QRect rect (x, y, m_sCell, m_sCell);
+ if (edge & (1 << Detached)) { // Shade a cell, as in XSudoku.
+ m_p->fillRect (rect, QColor ("#DDDDDD"));
+ }
+ m_p->setPen (m_light); // First draw every cell light.
+ m_p->drawRect (rect);
+ m_p->setPen (m_heavy); // Draw block boundaries heavy.
+ if (edge & (1<drawLine (x, y, x, y + m_sCell);
+ if (edge & (1<drawLine (x+m_sCell, y, x+m_sCell, y+m_sCell);
+ if (edge & (1<drawLine (x, y, x+m_sCell, y);
+ if (edge & (1<drawLine (x, y+m_sCell, x+m_sCell, y+m_sCell);
+}
+
+void PuzzlePrinter::drawValues (const ksudoku::Game& game, const SKGraph* graph)
+{
+ const QString labels = (graph->base() <= 3) ? "123456789" :
+ "ABCDEFGHIJKLMNOPQRSTUVWXY";
+ // Set font size 60% height of cell.
+ QFont f = m_p->font();
+ f.setPixelSize ((m_sCell * 6) / 10);
+ m_p->setFont (f);
+
+ for (int n = 0; n < graph->size(); n++) {
+ int v = game.value (n) - 1;
+ if (v < 0) {
+ continue; // Skip empty or unused cells.
+ }
+
+ // Draw original puzzle values heavy: filled-in/solution values light.
+ int x = m_topX + m_sCell * graph->cellPosX (n);
+ int y = m_topY + m_sCell * graph->cellPosY (n);
+ QRect rect (x, y, m_sCell, m_sCell);
+ m_p->setPen (game.given (n) ? m_heavy : m_light);
+ m_p->drawText (rect, Qt::AlignCenter, labels.mid (v, 1));
+ }
+}
+
+void PuzzlePrinter::drawKillerSudokuCages (const SKGraph* graph,
+ const QVector<int> & edges)
+{
+ // Killer Sudokus have cages AND groups: so the cages are drawn differently.
+ // We keep the outer wall of the cage on our left and draw a dashed line
+ // just inside that boundary. This reduces ugly criss-crossing of lines.
+ //
+ // Directions and related arrays are all in clockwise order.
+ enum Direction {East, South, West, North, nDirections};
+ const Direction rightTurn [nDirections] = {South, West, North, East};
+ const Direction leftTurn [nDirections] = {North, East, South, West};
+ const int wallOnLeft [nDirections] =
+ {1 << Above, 1 << Right, 1 << Below, 1 << Left};
+ const int wallAhead [nDirections] =
+ {1 << Right, 1 << Below, 1 << Left, 1 << Above};
+
+ const int deltaX [nDirections] = {+1, 0, -1, 0};
+ const int deltaY [nDirections] = {0, +1, 0, -1};
+
+ int cellInc [nDirections] = {graph->order(), +1, -graph->order(), -1};
+ int offset = (m_sCell + 6) / 12;
+ int longSide = m_sCell;
+ int shortSide = m_sCell - offset - offset;
+
+ m_p->setPen (m_dashes);
+
+ for (int n = 0; n < graph->cageCount(); n++) {
+ int topLeft = graph->cageTopLeft(n);
+ int cell = topLeft;
+ int edge = edges.at (cell);
+ int startX = m_topX + m_sCell * graph->cellPosX (cell) + offset;
+ int startY = m_topY + m_sCell * graph->cellPosY (cell) + offset;
+ int dx = 0;
+ int dy = 0;
+ QLine line (startX, startY, startX, startY);
+ Direction direction = East;
+
+ // Keep drawing until we get back to the starting cell and direction.
+ do {
+ // If there is a wall on the left, follow it.
+ if (edge & wallOnLeft [direction]) {
+ if (edge & wallAhead [direction]) {
+ // Go to wall (shortSide), draw line, turn right, new line.
+ dx = deltaX [direction] * shortSide;
+ dy = deltaY [direction] * shortSide;
+ line.setLine (line.x1(), line.y1(),
+ line.x2() + dx, line.y2() + dy);
+ m_p->drawLine (line);
+ direction = rightTurn [direction];
+ line.setLine (line.x2(), line.y2(), line.x2(), line.y2());
+ }
+ else {
+ // Extend to start of next cell (longSide).
+ dx = deltaX [direction] * longSide;
+ dy = deltaY [direction] * longSide;
+ line.setLine (line.x1(), line.y1(),
+ line.x2() + dx, line.y2() + dy);
+ cell = cell + cellInc [direction];
+ edge = edges.at (cell);
+ }
+ }
+ // Else, if there is no wall on the left ...
+ else {
+ // Draw line, turn left, new line, go to start of next cell.
+ m_p->drawLine (line);
+ direction = leftTurn [direction];
+ dx = deltaX [direction] * (longSide - shortSide);
+ dy = deltaY [direction] * (longSide - shortSide);
+ line.setLine (line.x2(), line.y2(),
+ line.x2() + dx, line.y2() + dy);
+ cell = cell + cellInc [direction];
+ edge = edges.at (cell);
+
+ }
+ } while (! ((cell == topLeft) && (direction == East)));
+ } // Draw next cage.
+}
+
+void PuzzlePrinter::drawCageLabel (const SKGraph* graph, int n,
+ bool killerStyle)
+{
+ if (graph->cage (n).size() < 2) {
+ return;
+ }
+
+ int topLeft = graph->cageTopLeft (n);
+ int cellX = m_topX + m_sCell * graph->cellPosX (topLeft);
+ int cellY = m_topY + m_sCell * graph->cellPosY (topLeft);
+
+ QString cLabel = QString::number (graph->cageValue (n));
+ if (! killerStyle) { // No operator is shown in KillerSudoku.
+ cLabel = cLabel + QString(" /-x+").mid(graph->cageOperator (n), 1);
+ }
+
+ QFont f = m_p->font();
+ f.setPixelSize ((m_sCell + 3)/4);
+ f.setBold (true);
+ m_p->setFont(f);
+ QFontMetrics fm(f);
+ int w = fm.width(cLabel);
+ int a = fm.ascent();
+ int m = (fm.width(QChar('1'))+1)/3; // Left margin = 1/3 width of '1'.
+
+ if (killerStyle) {
+ // Cover part of the dashed line, to make a background for the text.
+ m_p->fillRect(cellX + m, cellY + m, w + w/10, a /* h */, Qt::white);
+ }
+ // Note: Origin of text is on baseline to left of first character.
+ m_p->drawText (cellX + m, cellY + a, cLabel);
+}
+
+#include "puzzleprinter.moc"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksudoku-15.08.3/src/gui/puzzleprinter.h new/ksudoku-15.12.0/src/gui/puzzleprinter.h
--- old/ksudoku-15.08.3/src/gui/puzzleprinter.h 1970-01-01 01:00:00.000000000 +0100
+++ new/ksudoku-15.12.0/src/gui/puzzleprinter.h 2015-11-05 05:20:19.000000000 +0100
@@ -0,0 +1,88 @@
+/***************************************************************************
+ * Copyright 2005-2007 Francesco Rossi *
+ * Copyright 2006-2007 Mick Kappenburg *
+ * Copyright 2006-2007 Johannes Bergmeier *
+ * Copyright 2012 Ian Wadham *
+ * Copyright 2015 Ian Wadham *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef _PUZZLEPRINTER_H_
+#define _PUZZLEPRINTER_H_
+
+#include <QPen>
+
+namespace ksudoku {
+class Game;
+class Puzzle;
+}
+
+class SKGraph;
+class QWidget;
+
+class PuzzlePrinter : public QObject
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Default Constructor
+ */
+ PuzzlePrinter (QWidget * parent);
+
+ /**
+ * Default Destructor
+ */
+ virtual ~PuzzlePrinter();
+
+ void print (const ksudoku::Game & game);
+ void endPrint();
+
+private:
+ enum Edge {Left = 0, Right, Above, Below, Detached};
+
+ bool setupOutputDevices (int leastCellsToFit, int puzzleWidth);
+
+ void drawBlocks (const ksudoku::Puzzle * puzzle,
+ const SKGraph * graph);
+ void drawCages (const ksudoku::Puzzle * puzzle,
+ const SKGraph * graph, bool killerStyle);
+ void drawKillerSudokuCages (const SKGraph* graph,
+ const QVector<int> & edges);
+ void markEdges (const QVector<int> & cells,
+ const ksudoku::Puzzle * puzzle, const SKGraph * graph,
+ QVector<int> & edges);
+ void drawCell (int posX, int posY, int edge);
+ void drawValues (const ksudoku::Game & game, const SKGraph * graph);
+ void drawCageLabel (const SKGraph* graph, int n, bool killerStyle);
+
+ QWidget * m_parent;
+ QPrinter * m_printer;
+ QPainter * m_p;
+ int m_quadrant;
+ int m_across;
+ int m_down;
+ bool m_printMulti;
+ int m_sCell;
+ int m_topX;
+ int m_topY;
+ QPen m_heavy;
+ QPen m_light;
+ QPen m_dashes;
+};
+
+#endif // _PUZZLEPRINTER_H_
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksudoku-15.08.3/src/gui/welcomescreen.cpp new/ksudoku-15.12.0/src/gui/welcomescreen.cpp
--- old/ksudoku-15.08.3/src/gui/welcomescreen.cpp 2015-11-04 14:02:01.000000000 +0100
+++ new/ksudoku-15.12.0/src/gui/welcomescreen.cpp 2015-11-05 05:20:19.000000000 +0100
@@ -34,9 +34,24 @@
WelcomeScreen::WelcomeScreen(QWidget* parent, GameVariantCollection* collection)
: QFrame(parent), m_collection(collection)
{
- QItemDelegate* delegate = new GameVariantDelegate(this);
-
- setupUi(this);
+ setupUi(this); // Get gameListWidget by loading from welcomescreen.ui.
+
+ // Set the screen to display a multi-column list of puzzle-types, with
+ // vertical scrolling. GameVariantDelegate::sizeHint() calculates the
+ // number of columns and their width when it works out the size of the
+ // item's display-area.
+
+ QItemDelegate* delegate =
+ new GameVariantDelegate(this, gameListWidget->viewport());
+ gameListWidget->setWrapping(true);
+ gameListWidget->setResizeMode(QListView::Adjust);
+ gameListWidget->setUniformItemSizes(true);
+ gameListWidget->setFlow(QListView::LeftToRight);
+
+ // Avoid a resize loop (with the scrollbar appearing and disappearing)
+ // if ever the number of items and display-columns hits a bad combo.
+ gameListWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+
gameListWidget->setModel(m_collection);
gameListWidget->setItemDelegate(delegate);
gameListWidget->setVerticalScrollMode(QListView::ScrollPerPixel);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksudoku-15.08.3/src/shapes/Killer_4x4.desktop new/ksudoku-15.12.0/src/shapes/Killer_4x4.desktop
--- old/ksudoku-15.08.3/src/shapes/Killer_4x4.desktop 2015-11-04 14:02:01.000000000 +0100
+++ new/ksudoku-15.12.0/src/shapes/Killer_4x4.desktop 2015-11-05 05:20:19.000000000 +0100
@@ -17,7 +17,6 @@
Name[sr@ijekavianlatin]=Sićušni ubica
Name[sr@latin]=Sićušni ubica
Name[sv]=Liten mördare
-Name[tr]=Minik Killer
Name[uk]=Малий кілер
Name[x-test]=xxTiny Killerxx
Description=4x4 Sudoku, but cages must add to totals shown
@@ -38,7 +37,6 @@
Description[sr@ijekavianlatin]=Sudoku 4×4, ali kavezi moraju da dobiju prikazane zbirove
Description[sr@latin]=Sudoku 4×4, ali kavezi moraju da dobiju prikazane zbirove
Description[sv]=4x4 Sudoku, men avgränsningar måste adderas till visade summor
-Description[tr]=4x4 Sudoku, ama kafesler gösterilen toplamlara eklemek zorunda
Description[uk]=Судоку 4x4, але блоки мають складати сумі показане число
Description[x-test]=xx4x4 Sudoku, but cages must add to totals shownxx
Author=Ian Wadham
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksudoku-15.08.3/src/shapes/Killer_9x9.desktop new/ksudoku-15.12.0/src/shapes/Killer_9x9.desktop
--- old/ksudoku-15.08.3/src/shapes/Killer_9x9.desktop 2015-11-04 14:02:01.000000000 +0100
+++ new/ksudoku-15.12.0/src/shapes/Killer_9x9.desktop 2015-11-05 05:20:19.000000000 +0100
@@ -18,7 +18,6 @@
Name[sr@ijekavianlatin]=Sudoku ubica
Name[sr@latin]=Sudoku ubica
Name[sv]=Mördarsudoku
-Name[tr]=Killer Sudoku
Name[uk]=Судоку-кілер
Name[x-test]=xxKiller Sudokuxx
Description=Classic Sudoku, but cages must add to totals shown
@@ -39,7 +38,6 @@
Description[sr@ijekavianlatin]=Klasični sudoku, ali kavezi moraju da dobiju prikazane zbirove
Description[sr@latin]=Klasični sudoku, ali kavezi moraju da dobiju prikazane zbirove
Description[sv]=Klassisk Sudoku, men avgränsningar måste adderas till visade summor
-Description[tr]=Klasik Sudoku, ama kafesler gösterilen toplamlara eklemek zorunda
Description[uk]=Класичне судоку, але блоки мають складати у сумі показане число
Description[x-test]=xxClassic Sudoku, but cages must add to totals shownxx
Author=Ian Wadham
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksudoku-15.08.3/src/shapes/Mathdoku_4x4.desktop new/ksudoku-15.12.0/src/shapes/Mathdoku_4x4.desktop
--- old/ksudoku-15.08.3/src/shapes/Mathdoku_4x4.desktop 2015-11-04 14:02:01.000000000 +0100
+++ new/ksudoku-15.12.0/src/shapes/Mathdoku_4x4.desktop 2015-11-05 05:20:19.000000000 +0100
@@ -18,7 +18,6 @@
Name[sr@ijekavianlatin]=Matudoku 101
Name[sr@latin]=Matudoku 101
Name[sv]=Mattedoku 101
-Name[tr]=Matematikdoku 101
Name[uk]=Матдоку 101
Name[x-test]=xxMathdoku 101xx
Description=Size 4x4 grid, with calculated cages
@@ -39,7 +38,6 @@
Description[sr@ijekavianlatin]=Mreža 4×4, sa izračunatim kavezima
Description[sr@latin]=Mreža 4×4, sa izračunatim kavezima
Description[sv]=Storlek 4x4 med beräknade avgränsningar
-Description[tr]=Boyut 4x4, hesaplanan kafeslerle
Description[uk]=Ґратка розміром 4x4, із обчисленими блоками
Description[x-test]=xxSize 4x4 grid, with calculated cagesxx
Author=Ian Wadham
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ksudoku-15.08.3/src/shapes/Mathdoku_Settable.desktop new/ksudoku-15.12.0/src/shapes/Mathdoku_Settable.desktop
--- old/ksudoku-15.08.3/src/shapes/Mathdoku_Settable.desktop 2015-11-04 14:02:01.000000000 +0100
+++ new/ksudoku-15.12.0/src/shapes/Mathdoku_Settable.desktop 2015-11-05 05:20:19.000000000 +0100
@@ -18,7 +18,6 @@
Name[sr@ijekavianlatin]=Matudoku — podesiva veličina
Name[sr@latin]=Matudoku — podesiva veličina
Name[sv]=Mattedoku - Inställningsbar storlek
-Name[tr]=Matematikdoku - Ayarlanabilir Boyut
Name[uk]=Матдоку — змінний розмір
Name[x-test]=xxMathdoku - Settable Sizexx
Description=Size 3x3 to 9x9 grid, with calculated cages
@@ -39,7 +38,6 @@
Description[sr@ijekavianlatin]=Mreža od 3×3 do 9×9, sa izračunatim kavezima
Description[sr@latin]=Mreža od 3×3 do 9×9, sa izračunatim kavezima
Description[sv]=Storlek 3x3 till 9x9 med beräknade avgränsningar
-Description[tr]=Boyut 3x3 ile 9x9 arasında, hesaplanan kafeslerle
Description[uk]=Ґратка розміром від 3x3 до 9x9, із обчисленими блоками
Description[x-test]=xxSize 3x3 to 9x9 grid, with calculated cagesxx
Author=Ian Wadham