summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Wadham <[email protected]>2015-06-28 08:41:01 +1000
committerIan Wadham <[email protected]>2015-06-28 08:41:01 +1000
commit3497d744efd237fb76225b2e4ff8b545bc8f998f (patch)
tree5a619e0b12f90c4d3890b47ba45bb4634469ba98
parent291b38a97b8c5c644838c168ae797f3106899c47 (diff)
Stabilise the 2-D view and rendering of cages and highlights, for now.
Sudoku and Roxdoku puzzles are being drawn in the usual way. Mathdoku and Killer Sudoku puzzles have smaller symbols and markers, to allow space for the text of a cage-label (value and operator). There are some TODOs, mainly to show block boundaries in Killer Sudoku somehow.
-rw-r--r--src/gui/views/renderer.cpp58
-rw-r--r--src/gui/views/renderer.h10
-rw-r--r--src/gui/views/view2d.cpp51
3 files changed, 69 insertions, 50 deletions
diff --git a/src/gui/views/renderer.cpp b/src/gui/views/renderer.cpp
index 4fe81c6..b1ca663 100644
--- a/src/gui/views/renderer.cpp
+++ b/src/gui/views/renderer.cpp
@@ -25,6 +25,7 @@ Renderer::Renderer() {
m_renderer = new QSvgRenderer();
m_cache = new KPixmapCache("ksudoku-cache");
m_cache->setCacheLimit(3*1024);
+ m_mathdokuStyle = false;
if(!loadTheme(Settings::theme()))
kDebug() << "Failed to load any game theme!";
@@ -93,10 +94,7 @@ void Renderer::fillNameHashes() {
m_borderTypes << "column";
m_borderTypes << "block";
m_borderTypes << "special";
- // IDW test. m_borderTypes << "special";
- // m_borderTypes << "special_h"; // IDW test.
- m_borderTypes << "block"; // IDW test.
- // m_borderTypes << "cage"; // IDW test.
+ m_borderTypes << "block"; // Use block-type borders for cages.
m_borderTypes << "special";
m_borderTypes << "special";
m_borderTypes << QString();
@@ -104,8 +102,7 @@ void Renderer::fillNameHashes() {
m_borderTypes << "column_h";
m_borderTypes << "block_h";
m_borderTypes << "special_h";
- // IDW test. m_borderTypes << "special_h";
- m_borderTypes << "block_h";
+ m_borderTypes << "block_h"; // Use block-type borders for cages.
m_borderTypes << "special_h";
m_borderTypes << "special_h";
m_specialNames << "cell";
@@ -237,7 +234,10 @@ QPixmap Renderer::renderSymbol(int symbol, int size, int max, SymbolType type) c
}
QPixmap Renderer::renderSymbolOn(QPixmap pixmap, int symbol, int color, int max, SymbolType type) const {
- int size = pixmap.width();
+ // We use a smaller size of symbol in Mathdoku and Killer
+ // Sudoku, to allow space for the cage labels.
+ int size = m_mathdokuStyle ? (pixmap.width()+1)*3/4 : pixmap.width();
+ int offset = m_mathdokuStyle ? (pixmap.width()+7)/8 : 0;
QPixmap symbolPixmap = renderSymbol(symbol, size, max, type);
if(color) {
// TODO this does not work, need some other way, maybe hardcode color into NumberType
@@ -251,7 +251,7 @@ QPixmap Renderer::renderSymbolOn(QPixmap pixmap, int symbol, int color, int max,
return symbolPixmap;
} else {
QPainter p(&pixmap);
- p.drawPixmap(0, 0, symbolPixmap);
+ p.drawPixmap(offset, offset, symbolPixmap);
p.end();
return pixmap;
}
@@ -305,8 +305,10 @@ QPixmap Renderer::renderMarker(int symbol, int range, int size) const {
QPixmap Renderer::renderMarkerOn(QPixmap pixmap, int symbol, int range, int color) const {
// TODO maybe it would be good to directly integrate the renderMarker implementation and
// make renderMarker be based on this method. (same for renderSymbol and renderSymbolOn)
- // IDW TODO - Use smaller size in Mathdoku and Killer only.
- int size = pixmap.width() * 8 / 10; // IDW test. ;
+
+ // We use a smaller size of marker in Mathdoku and Killer
+ // Sudoku, to allow space for the cage labels.
+ int size = m_mathdokuStyle ? (pixmap.width()+1)*3/4 : pixmap.width();
QPixmap symbolPixmap = renderMarker(symbol, range, size);
if(color) {
QPainter p(&symbolPixmap);
@@ -319,15 +321,43 @@ QPixmap Renderer::renderMarkerOn(QPixmap pixmap, int symbol, int range, int colo
return symbolPixmap;
} else {
QPainter p(&pixmap);
- // IDW TODO - Use offset from 0,0 in Mathdoku and Killer only.
- // IDW test. p.drawPixmap(0, 0, symbolPixmap);
- int offset = (size + 10)/10; // IDW test.
- p.drawPixmap(offset, 2*offset, symbolPixmap); // IDW test.
+ // Offset the marker from 0,0 in Mathdoku and Killer Sudoku.
+ int offset = m_mathdokuStyle ? (size + 7)/8 : 0;
+ p.drawPixmap(offset, 2*offset, symbolPixmap);
p.end();
return pixmap;
}
}
+QPixmap Renderer::renderCageLabelOn(QPixmap pixmap, const QString & cageLabel)
+{
+ // TODO - Do font setup once during resize? Put 0+-x/ in themes?
+ int size = pixmap.width();
+ QPainter p(&pixmap);
+ p.setPen(QString("white")); // Text is white on a dark rectangle.
+ p.setBrush(Qt::SolidPattern);
+
+ // Cage label uses top 1/4 of pixmap and text is 1/6 height of pixmap.
+ QFont f = p.font();
+ f.setBold(true);
+ f.setPixelSize((size+5)/6);
+ p.setFont(f);
+
+ QFontMetrics fm(f);
+ int w = fm.width(cageLabel); // Width of text.
+ int h = fm.height(); // Total height of font.
+ int a = fm.ascent(); // Height from baseline of font.
+ int m = fm.width(QChar('1'))/2; // Left-right margin = 1/2 width of '1'.
+
+ // Paint background rect: text must be visible in light and dark themes.
+ p.fillRect(size/6 - m, (size + 3)/4 - a, w + 2*m, h, Qt::darkGray);
+ // Note: Origin of text is on baseline to left of first character.
+ p.drawText(size/6, (size+3)/4, cageLabel);
+
+ p.end();
+ return pixmap;
+}
+
QPixmap Renderer::renderBorder(int border, GroupTypes type, int size) const {
if(!m_renderer->isValid() || size == 0) return QPixmap();
diff --git a/src/gui/views/renderer.h b/src/gui/views/renderer.h
index dbc0b96..cbc8709 100644
--- a/src/gui/views/renderer.h
+++ b/src/gui/views/renderer.h
@@ -37,7 +37,7 @@ enum GroupType {
GroupColumn = 0x02,
GroupBlock = 0x03,
GroupSpecial = 0x04,
- GroupCage = 0x05, // IDW test.
+ GroupCage = 0x05, // For Mathdoku and Killer Sudoku only.
GroupUnhighlightedMask = 0x07,
GroupHighlight = 0x08
};
@@ -80,6 +80,11 @@ public:
bool loadTheme(const QString& themeName);
+ // In Mathdoku style, symbols and markers are drawn smaller than usual
+ // and re-positioned, to allow space at the top left of a cell for a
+ // cage label. The label contains the value and operator clues.
+ void setMathdokuStyle(bool onOff) { m_mathdokuStyle = onOff; }
+
QPixmap renderBackground(const QSize& size) const;
QPixmap renderSpecial(SpecialType type, int size) const;
@@ -91,6 +96,8 @@ public:
QPixmap renderMarker(int symbol, int range, int size) const;
QPixmap renderMarkerOn(QPixmap pixmap, int symbol, int range, int color) const;
+ QPixmap renderCageLabelOn(QPixmap pixmap, const QString & cageLabel);
+
QPixmap renderSpecial3D(SpecialType type, int size) const;
private:
Renderer();
@@ -115,6 +122,7 @@ private:
QString m_currentTheme;
QSvgRenderer* m_renderer;
KPixmapCache* m_cache;
+ bool m_mathdokuStyle;
};
}
diff --git a/src/gui/views/view2d.cpp b/src/gui/views/view2d.cpp
index 701ad35..43690a9 100644
--- a/src/gui/views/view2d.cpp
+++ b/src/gui/views/view2d.cpp
@@ -155,20 +155,7 @@ void CellGraphicsItem::updatePixmap() {
default: break; // TODO maybe assert as this is not allowed to occur
}
if (! m_cageLabel.isEmpty()) {
- // TODO - Do this in gui/views/renderer.cpp.
- // TODO - More work on layout of targets, markers and symbols.
- // TODO - Leave everything unchanged for pure Sudoku puzzles.
- // TODO - Do font setup once during resize? Put 0+-x/ in themes?
- // TODO - Draw a background rectangle for the target text?
- int size = pic.width();
- QPainter p(&pic);
- p.setPen(QString("white")); // TODO - Scribble needs black?
- QFont f = p.font();
- f.setBold(true);
- f.setPixelSize((size+5)/6);
- p.setFont(f);
- p.drawText(size/6, (size+4)/5, m_cageLabel);
- p.end();
+ pic = Renderer::instance()->renderCageLabelOn(pic, m_cageLabel);
}
setPixmap(pic);
@@ -217,9 +204,8 @@ GroupGraphicsItem::GroupGraphicsItem(QVector<QPoint> cells, bool isCage) {
detectType();
if (isCage) {
// Draw border around cage, even if it is all in one row or column.
- // IDW test. m_type = GroupBlock;
- m_type = GroupCage; // IDW test.
- setZValue(4); // IDW test.
+ m_type = GroupCage;
+ setZValue(4);
}
createContour();
@@ -251,15 +237,10 @@ void GroupGraphicsItem::detectType() {
if(x==-1) m_type |= GroupRow;
if(y==-1) m_type |= GroupColumn;
- // TODO - Does this code *really* affect highlights? See setHighlight().
// Row and column highlights must go above the GroupBlock boundary-line.
- // IDW test. if(m_type == GroupColumn) setZValue(4);
- // IDW test. else if(m_type == GroupRow) setZValue(4);
- // IDW test. else if(m_type == GroupBlock) setZValue(3);
- //
- // TODO - It really looks better to have the block highlight on top of
- // the row and column, especially with cages or irregular blocks.
- // Might also be a good idea to reduce opacity of row and column.
+ // It really looks better to have the block highlight on top of the row
+ // and column highlights, especially with cages or jigsaw-type blocks.
+ // TODO - Might also be a good idea to reduce opacity of row and column.
if(m_type == GroupColumn) setZValue(3);
else if(m_type == GroupRow) setZValue(3);
else if(m_type == GroupBlock) setZValue(4);
@@ -281,10 +262,9 @@ void GroupGraphicsItem::createContour() {
idx[7] = m_cells.indexOf(QPoint(x, y+1)); // South.
idx[8] = m_cells.indexOf(QPoint(x+1, y+1)); // South East.
- // IDW test. if(idx[1] == -1 && idx[3] == -1 && idx[5] == -1 && idx[7] == -1)
- // IDW test. if(!m_isCage && // A cage can consist of one cell and a border.
- if((m_type != GroupCage) && // A cage can consist of one cell and a border.
- idx[1] == -1 && idx[3] == -1 && idx[5] == -1 && idx[7] == -1) // IDW test.
+ // A cage can consist of one cell with a border.
+ if((m_type != GroupCage) &&
+ idx[1] == -1 && idx[3] == -1 && idx[5] == -1 && idx[7] == -1)
{
// No adjoining neighbour to N, S, E or W.
m_type = GroupSpecial; // Used in the "X" of XSudoku.
@@ -322,7 +302,7 @@ void GroupGraphicsItem::createSegment(const QPoint& pos, int shape) {
segment.standard = 0;
break;
case GroupBlock:
- case GroupCage: // IDW test.
+ case GroupCage:
segment.standard = (shape == 15) ? 0 // No middle.
: new QGraphicsPixmapItem(this);
break;
@@ -359,13 +339,11 @@ void GroupGraphicsItem::setHighlight(bool highlight) {
if ((m_type & GroupBlock) == GroupBlock) {
// Block highlight goes on top of row, column and special
// highlights. Block boundary-line goes underneath them.
- // IDW test. setZValue(highlight ? 6 : 3);
setZValue(highlight ? 8 : 4);
}
- // IDW test. if ((m_type & GroupSpecial) == GroupSpecial) {
- if (m_type == GroupSpecial) { // IDW test.
+ if (m_type == GroupSpecial) {
// Special highlight goes on top of unhighlighted special cell.
- setZValue(highlight ? 5 : 4);
+ setZValue(highlight ? 9 : 4);
}
}
if(segment->standard) {
@@ -452,6 +430,8 @@ void View2DScene::init(const Game& game) {
addItem(m_cellLayer);
SKGraph* g = m_game.puzzle()->graph();
+ Renderer::instance()->setMathdokuStyle((g->specificType() == Mathdoku)
+ || (g->specificType() == KillerSudoku));
m_cells.resize(m_game.size());
m_cursorPos = -1;
for(int i = 0; i < m_game.size(); ++i) {
@@ -476,6 +456,8 @@ void View2DScene::init(const Game& game) {
}
m_groups.resize(g->cliqueCount() + g->cageCount());
+ // IDW TODO - Draw Killer Sudoku cages inside cell borders?
+ // Anyway, show 3x3 and 2x2 blocks in Killer Sudoku somehow.
for(int i = 0; i < g->cliqueCount(); ++i) {
// Set the shape of each group.
QVector<int> idx = g->clique(i);
@@ -485,7 +467,6 @@ void View2DScene::init(const Game& game) {
}
m_groups[i] = new GroupGraphicsItem(pts);
m_groups[i]->setParentItem(m_groupLayer);
- // IDW TODO - Draw Killer Sudoku cages inside cell borders?
// Avoid ugly crossings of cages and blocks in Killer Sudoku.
// Show borders of blocks only if there are no cages present.
m_groups[i]->hideBlockBorder((g->cageCount() > 0));