Implemented a value hint, changed colors.

* When you press on a value, that value will be shown with a
  highlighted background across the board until another value is set.
* Changed the colors to those from the Haiku logo rather than the BeOS
  logo. This makes it a bit more colorful which one might need to get
  used to -- comments welcome.
This commit is contained in:
Axel Dörfler
2012-06-06 00:35:51 +02:00
parent 0ba36860ad
commit 2996f64881
2 changed files with 111 additions and 36 deletions
+106 -36
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2007-2010, Axel Dörfler, [email protected]. * Copyright 2007-2012, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -28,9 +28,17 @@
#include <String.h> #include <String.h>
const uint32 kMsgCheckSolved = 'chks'; static const uint32 kMsgCheckSolved = 'chks';
const uint32 kStrongLineSize = 2; static const uint32 kStrongLineSize = 2;
static const rgb_color kBackgroundColor = {255, 255, 240};
static const rgb_color kHintColor = {255, 115, 0};
static const rgb_color kValueColor = {0, 91, 162};
static const rgb_color kValueCompletedColor = {55, 140, 35};
static const rgb_color kInvalidValueColor = {200, 0, 0};
static const rgb_color kValueHintBackgroundColor = {255, 215, 127};
static const rgb_color kHintValueHintBackgroundColor = {255, 235, 185};
extern const char* kSignature; extern const char* kSignature;
@@ -103,6 +111,7 @@ SudokuView::InitObject(const BMessage* archive)
{ {
fField = NULL; fField = NULL;
fShowHintX = ~0UL; fShowHintX = ~0UL;
fValueHintValue = ~0UL;
fLastHintValue = ~0UL; fLastHintValue = ~0UL;
fLastField = ~0UL; fLastField = ~0UL;
fKeyboardX = 0; fKeyboardX = 0;
@@ -131,9 +140,8 @@ SudokuView::InitObject(const BMessage* archive)
SetViewColor(B_TRANSPARENT_COLOR); SetViewColor(B_TRANSPARENT_COLOR);
// to avoid flickering // to avoid flickering
rgb_color color = { 255, 255, 240 }; fBackgroundColor = kBackgroundColor;
fBackgroundColor = color; SetLowColor(fBackgroundColor);
SetLowColor(color);
FrameResized(0, 0); FrameResized(0, 0);
} }
@@ -212,6 +220,7 @@ SudokuView::SetTo(entry_ref& ref)
_PushUndo(); _PushUndo();
status = fField->SetTo(_BaseCharacter(), buffer); status = fField->SetTo(_BaseCharacter(), buffer);
fValueHintValue = ~0UL;
Invalidate(); Invalidate();
fclose(file); fclose(file);
return status; return status;
@@ -234,6 +243,7 @@ SudokuView::SetTo(const char* data)
_PushUndo(); _PushUndo();
status = fField->SetTo(_BaseCharacter(), buffer); status = fField->SetTo(_BaseCharacter(), buffer);
fValueHintValue = ~0UL;
Invalidate(); Invalidate();
return status; return status;
} }
@@ -250,6 +260,7 @@ SudokuView::SetTo(SudokuField* field)
fField = field; fField = field;
fBlockSize = fField->BlockSize(); fBlockSize = fField->BlockSize();
fValueHintValue = ~0UL;
FrameResized(0, 0); FrameResized(0, 0);
Invalidate(); Invalidate();
return B_OK; return B_OK;
@@ -377,7 +388,7 @@ SudokuView::SaveTo(BDataIO& stream, uint32 exportAs)
text << "<td width=\"" << divider << "\" "; text << "<td width=\"" << divider << "\" ";
text << "class=\"sudoku sudoku_empty " << style; text << "class=\"sudoku sudoku_empty " << style;
text << "\">\n&nbsp;"; text << "\">\n&nbsp;";
} else if (fField->FlagsAt(x, y) & kInitialValue) { } else if (fField->IsInitialValue(x, y)) {
text << "<td width=\"" << divider << "\" "; text << "<td width=\"" << divider << "\" ";
text << "class=\"sudoku sudoku_initial " << style text << "class=\"sudoku sudoku_initial " << style
<< "\">\n"; << "\">\n";
@@ -543,7 +554,7 @@ SudokuView::ClearChanged()
for (uint32 y = 0; y < fField->Size(); y++) { for (uint32 y = 0; y < fField->Size(); y++) {
for (uint32 x = 0; x < fField->Size(); x++) { for (uint32 x = 0; x < fField->Size(); x++) {
if ((fField->FlagsAt(x, y) & kInitialValue) == 0) if (!fField->IsInitialValue(x, y))
fField->SetValueAt(x, y, 0); fField->SetValueAt(x, y, 0);
} }
} }
@@ -612,8 +623,9 @@ SudokuView::FrameResized(float /*width*/, float /*height*/)
// font for numbers // font for numbers
uint32 size = fField->Size(); uint32 size = fField->Size();
fWidth = (Bounds().Width() - kStrongLineSize * (fBlockSize - 1)) / size; fWidth = (Bounds().Width() + 2 - kStrongLineSize * (fBlockSize - 1)) / size;
fHeight = (Bounds().Height() - kStrongLineSize * (fBlockSize - 1)) / size; fHeight = (Bounds().Height() + 2 - kStrongLineSize * (fBlockSize - 1))
/ size;
_FitFont(fFieldFont, fWidth - 2, fHeight - 2); _FitFont(fFieldFont, fWidth - 2, fHeight - 2);
font_height fontHeight; font_height fontHeight;
@@ -641,8 +653,8 @@ SudokuView::FrameResized(float /*width*/, float /*height*/)
BPoint BPoint
SudokuView::_LeftTop(uint32 x, uint32 y) SudokuView::_LeftTop(uint32 x, uint32 y)
{ {
return BPoint(x * fWidth + x / fBlockSize * kStrongLineSize + 1, return BPoint(x * fWidth - 1 + x / fBlockSize * kStrongLineSize + 1,
y * fHeight + y / fBlockSize * kStrongLineSize + 1); y * fHeight - 1 + y / fBlockSize * kStrongLineSize + 1);
} }
@@ -678,6 +690,22 @@ SudokuView::_InvalidateField(uint32 x, uint32 y)
} }
void
SudokuView::_InvalidateValue(uint32 value, bool invalidateHint,
uint32 fieldX, uint32 fieldY)
{
for (uint32 y = 0; y < fField->Size(); y++) {
for (uint32 x = 0; x < fField->Size(); x++) {
if (fField->ValueAt(x, y) == value || (x == fieldX && y == fieldY))
Invalidate(_Frame(x, y));
else if (invalidateHint && fField->ValueAt(x, y) == 0
&& fField->HasHint(x, y, value))
Invalidate(_Frame(x, y));
}
}
}
void void
SudokuView::_InvalidateKeyboardFocus(uint32 x, uint32 y) SudokuView::_InvalidateKeyboardFocus(uint32 x, uint32 y)
{ {
@@ -723,6 +751,22 @@ SudokuView::_GetFieldFor(BPoint where, uint32& x, uint32& y)
} }
void
SudokuView::_SetValueHintValue(uint32 value)
{
if (value == fValueHintValue)
return;
if (fValueHintValue != ~0UL)
_InvalidateValue(fValueHintValue, true);
fValueHintValue = value;
if (fValueHintValue != ~0UL)
_InvalidateValue(fValueHintValue, true);
}
void void
SudokuView::_RemoveHint() SudokuView::_RemoveHint()
{ {
@@ -801,6 +845,15 @@ SudokuView::MouseDown(BPoint where)
Looper()->CurrentMessage()->FindInt32("clicks", &clicks); Looper()->CurrentMessage()->FindInt32("clicks", &clicks);
} }
if (buttons == B_PRIMARY_MOUSE_BUTTON && clicks == 1) {
uint32 value = fField->ValueAt(x, y);
if (value != 0) {
// Toggle value hint
_SetValueHintValue(fValueHintValue == value ? ~0UL : value);
return;
}
}
uint32 hintX, hintY; uint32 hintX, hintY;
if (!_GetHintFieldFor(where, x, y, hintX, hintY)) if (!_GetHintFieldFor(where, x, y, hintX, hintY))
return; return;
@@ -813,9 +866,10 @@ SudokuView::MouseDown(BPoint where)
|| (buttons & (B_SECONDARY_MOUSE_BUTTON || (buttons & (B_SECONDARY_MOUSE_BUTTON
| B_TERTIARY_MOUSE_BUTTON)) != 0) { | B_TERTIARY_MOUSE_BUTTON)) != 0) {
// double click or other buttons set a value // double click or other buttons set a value
if ((fField->FlagsAt(x, y) & kInitialValue) == 0) { if (!fField->IsInitialValue(x, y)) {
bool wasCompleted; bool wasCompleted;
if (fField->ValueAt(x, y) > 0) { if (fField->ValueAt(x, y) > 0) {
// Remove value
value = fField->ValueAt(x, y) - 1; value = fField->ValueAt(x, y) - 1;
wasCompleted = fField->IsValueCompleted(value + 1); wasCompleted = fField->IsValueCompleted(value + 1);
@@ -823,6 +877,7 @@ SudokuView::MouseDown(BPoint where)
fShowHintX = x; fShowHintX = x;
fShowHintY = y; fShowHintY = y;
} else { } else {
// Set value
wasCompleted = fField->IsValueCompleted(value + 1); wasCompleted = fField->IsValueCompleted(value + 1);
fField->SetValueAt(x, y, value + 1); fField->SetValueAt(x, y, value + 1);
@@ -834,8 +889,11 @@ SudokuView::MouseDown(BPoint where)
fLastField = field; fLastField = field;
} }
if (value + 1 != fValueHintValue)
_SetValueHintValue(~0UL);
if (wasCompleted != fField->IsValueCompleted(value + 1)) if (wasCompleted != fField->IsValueCompleted(value + 1))
Invalidate(); _InvalidateValue(value + 1, false, x, y);
else else
_InvalidateField(x, y); _InvalidateField(x, y);
} }
@@ -852,7 +910,12 @@ SudokuView::MouseDown(BPoint where)
hintMask &= ~valueMask; hintMask &= ~valueMask;
fField->SetHintMaskAt(x, y, hintMask); fField->SetHintMaskAt(x, y, hintMask);
_InvalidateHintField(x, y, hintX, hintY);
if (value + 1 != fValueHintValue) {
_SetValueHintValue(~0UL);
_InvalidateHintField(x, y, hintX, hintY);
} else
_InvalidateField(x, y);
fLastHintValue = value; fLastHintValue = value;
fLastField = field; fLastField = field;
@@ -879,8 +942,9 @@ SudokuView::MouseMoved(BPoint where, uint32 transit,
fKeyboardX = x; fKeyboardX = x;
fKeyboardY = y; fKeyboardY = y;
} }
if (!isField if (!isField
|| (fField->FlagsAt(x, y) & kInitialValue) != 0 || fField->IsInitialValue(x, y)
|| (!fShowCursor && fField->ValueAt(x, y) != 0)) { || (!fShowCursor && fField->ValueAt(x, y) != 0)) {
_RemoveHint(); _RemoveHint();
return; return;
@@ -919,7 +983,7 @@ void
SudokuView::_InsertKey(char rawKey, int32 modifiers) SudokuView::_InsertKey(char rawKey, int32 modifiers)
{ {
if (!fEditable || !_ValidCharacter(rawKey) if (!fEditable || !_ValidCharacter(rawKey)
|| (fField->FlagsAt(fKeyboardX, fKeyboardY) & kInitialValue) != 0) || fField->IsInitialValue(fKeyboardX, fKeyboardY))
return; return;
uint32 value = rawKey - _BaseCharacter(); uint32 value = rawKey - _BaseCharacter();
@@ -1144,9 +1208,12 @@ SudokuView::_DrawHints(uint32 x, uint32 y)
for (uint32 j = 0; j < fBlockSize; j++) { for (uint32 j = 0; j < fBlockSize; j++) {
for (uint32 i = 0; i < fBlockSize; i++) { for (uint32 i = 0; i < fBlockSize; i++) {
uint32 value = j * fBlockSize + i; uint32 value = j * fBlockSize + i;
if (hintMask & (1UL << value)) if (hintMask & (1UL << value)) {
SetHighColor(200, 0, 0); // if (value + 1 == fValueHintValue)
else { // SetHighColor(kValueHintBackgroundColor);
// else
SetHighColor(kHintColor);
}else {
if (!showAll) if (!showAll)
continue; continue;
@@ -1170,18 +1237,14 @@ SudokuView::_DrawHints(uint32 x, uint32 y)
void void
SudokuView::Draw(BRect /*updateRect*/) SudokuView::Draw(BRect /*updateRect*/)
{ {
// draw one pixel border otherwise not covered
// by lines and fields
SetLowColor(fBackgroundColor);
StrokeRect(Bounds(), B_SOLID_LOW);
// draw lines // draw lines
uint32 size = fField->Size(); uint32 size = fField->Size();
SetLowColor(fBackgroundColor);
SetHighColor(0, 0, 0); SetHighColor(0, 0, 0);
float width = fWidth; float width = fWidth - 1;
for (uint32 x = 1; x < size; x++) { for (uint32 x = 1; x < size; x++) {
if (x % fBlockSize == 0) { if (x % fBlockSize == 0) {
FillRect(BRect(width, 0, width + kStrongLineSize, FillRect(BRect(width, 0, width + kStrongLineSize,
@@ -1193,7 +1256,7 @@ SudokuView::Draw(BRect /*updateRect*/)
width += fWidth; width += fWidth;
} }
float height = fHeight; float height = fHeight - 1;
for (uint32 y = 1; y < size; y++) { for (uint32 y = 1; y < size; y++) {
if (y % fBlockSize == 0) { if (y % fBlockSize == 0) {
FillRect(BRect(0, height, Bounds().Width(), FillRect(BRect(0, height, Bounds().Width(),
@@ -1209,39 +1272,46 @@ SudokuView::Draw(BRect /*updateRect*/)
for (uint32 y = 0; y < size; y++) { for (uint32 y = 0; y < size; y++) {
for (uint32 x = 0; x < size; x++) { for (uint32 x = 0; x < size; x++) {
uint32 value = fField->ValueAt(x, y);
rgb_color backgroundColor = fBackgroundColor;
if (value == fValueHintValue)
backgroundColor = kValueHintBackgroundColor;
else if (value == 0 && fField->HasHint(x, y, fValueHintValue))
backgroundColor = kHintValueHintBackgroundColor;
if (((fShowCursor && x == fShowHintX && y == fShowHintY) if (((fShowCursor && x == fShowHintX && y == fShowHintY)
|| (fShowKeyboardFocus && x == fKeyboardX || (fShowKeyboardFocus && x == fKeyboardX
&& y == fKeyboardY)) && y == fKeyboardY))
&& (fField->FlagsAt(x, y) & kInitialValue) == 0) { && !fField->IsInitialValue(x, y)) {
// TODO: make color more intense // TODO: make color more intense
SetLowColor(tint_color(fBackgroundColor, B_DARKEN_2_TINT)); SetLowColor(tint_color(backgroundColor, B_DARKEN_2_TINT));
FillRect(_Frame(x, y), B_SOLID_LOW); FillRect(_Frame(x, y), B_SOLID_LOW);
} else { } else {
SetLowColor(fBackgroundColor); SetLowColor(backgroundColor);
FillRect(_Frame(x, y), B_SOLID_LOW); FillRect(_Frame(x, y), B_SOLID_LOW);
} }
if (fShowKeyboardFocus && x == fKeyboardX && y == fKeyboardY) if (fShowKeyboardFocus && x == fKeyboardX && y == fKeyboardY)
_DrawKeyboardFocus(); _DrawKeyboardFocus();
uint32 value = fField->ValueAt(x, y);
if (value == 0) { if (value == 0) {
_DrawHints(x, y); _DrawHints(x, y);
continue; continue;
} }
SetFont(&fFieldFont); SetFont(&fFieldFont);
if ((fField->FlagsAt(x, y) & kInitialValue) != 0) if (fField->IsInitialValue(x, y))
SetHighColor(0, 0, 0); SetHighColor(0, 0, 0);
else { else {
if ((fHintFlags & kMarkInvalid) == 0 if ((fHintFlags & kMarkInvalid) == 0
|| fField->ValidMaskAt(x, y) & (1UL << (value - 1))) { || fField->IsValid(x, y, value)) {
if (fField->IsValueCompleted(value)) if (fField->IsValueCompleted(value))
SetHighColor(60, 60, 150); SetHighColor(kValueCompletedColor);
else else
SetHighColor(0, 0, 220); SetHighColor(kValueColor);
} else } else
SetHighColor(200, 0, 0); SetHighColor(kInvalidValueColor);
} }
char text[2]; char text[2];
+5
View File
@@ -94,8 +94,12 @@ private:
void _InvalidateHintField(uint32 x, uint32 y, void _InvalidateHintField(uint32 x, uint32 y,
uint32 hintX, uint32 hintY); uint32 hintX, uint32 hintY);
void _InvalidateField(uint32 x, uint32 y); void _InvalidateField(uint32 x, uint32 y);
void _InvalidateValue(uint32 value,
bool invalidateHint = false,
uint32 x = ~0UL, uint32 y = ~0UL);
void _InvalidateKeyboardFocus(uint32 x, uint32 y); void _InvalidateKeyboardFocus(uint32 x, uint32 y);
void _InsertKey(char rawKey, int32 modifiers); void _InsertKey(char rawKey, int32 modifiers);
void _SetValueHintValue(uint32 value);
void _RemoveHint(); void _RemoveHint();
bool _GetHintFieldFor(BPoint where, uint32 x, bool _GetHintFieldFor(BPoint where, uint32 x,
uint32 y, uint32& hintX, uint32& hintY); uint32 y, uint32& hintX, uint32& hintY);
@@ -127,6 +131,7 @@ private:
uint32 fShowHintY; uint32 fShowHintY;
uint32 fLastHintValue; uint32 fLastHintValue;
bool fLastHintValueSet; bool fLastHintValueSet;
uint32 fValueHintValue;
uint32 fLastField; uint32 fLastField;
uint32 fKeyboardX; uint32 fKeyboardX;
uint32 fKeyboardY; uint32 fKeyboardY;