* Renamed "Store Current" to "Snapshot Current", and "Restore Saved" to
"Restore Snapshot". * Implemented a simple undo/redo. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22987 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -2,6 +2,8 @@ SubDir HAIKU_TOP src apps sudoku ;
|
|||||||
|
|
||||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||||
|
|
||||||
|
UsePrivateHeaders shared ;
|
||||||
|
|
||||||
Application Sudoku :
|
Application Sudoku :
|
||||||
CenteredViewContainer.cpp
|
CenteredViewContainer.cpp
|
||||||
ProgressWindow.cpp
|
ProgressWindow.cpp
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ SudokuView::SetTo(entry_ref& ref)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_PushUndo();
|
||||||
status = fField->SetTo(_BaseCharacter(), buffer);
|
status = fField->SetTo(_BaseCharacter(), buffer);
|
||||||
Invalidate();
|
Invalidate();
|
||||||
return status;
|
return status;
|
||||||
@@ -164,6 +165,7 @@ SudokuView::SetTo(const char* data)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
_PushUndo();
|
||||||
status = fField->SetTo(_BaseCharacter(), buffer);
|
status = fField->SetTo(_BaseCharacter(), buffer);
|
||||||
Invalidate();
|
Invalidate();
|
||||||
return status;
|
return status;
|
||||||
@@ -176,6 +178,7 @@ SudokuView::SetTo(SudokuField* field)
|
|||||||
if (field == NULL || field == fField)
|
if (field == NULL || field == fField)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
_PushUndo();
|
||||||
delete fField;
|
delete fField;
|
||||||
fField = field;
|
fField = field;
|
||||||
|
|
||||||
@@ -222,6 +225,8 @@ SudokuView::SaveTo(entry_ref& ref, bool asText)
|
|||||||
void
|
void
|
||||||
SudokuView::ClearChanged()
|
SudokuView::ClearChanged()
|
||||||
{
|
{
|
||||||
|
_PushUndo();
|
||||||
|
|
||||||
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->FlagsAt(x, y) & kInitialValue) == 0)
|
||||||
@@ -236,6 +241,7 @@ SudokuView::ClearChanged()
|
|||||||
void
|
void
|
||||||
SudokuView::ClearAll()
|
SudokuView::ClearAll()
|
||||||
{
|
{
|
||||||
|
_PushUndo();
|
||||||
fField->Reset();
|
fField->Reset();
|
||||||
Invalidate();
|
Invalidate();
|
||||||
}
|
}
|
||||||
@@ -413,6 +419,55 @@ SudokuView::_RemoveHint()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SudokuView::_UndoRedo(BObjectList<BMessage>& undos,
|
||||||
|
BObjectList<BMessage>& redos)
|
||||||
|
{
|
||||||
|
if (undos.IsEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
BMessage* undo = undos.RemoveItemAt(undos.CountItems() - 1);
|
||||||
|
|
||||||
|
BMessage* redo = new BMessage;
|
||||||
|
if (fField->Archive(redo, true) == B_OK)
|
||||||
|
redos.AddItem(redo);
|
||||||
|
|
||||||
|
SudokuField field(undo);
|
||||||
|
delete undo;
|
||||||
|
|
||||||
|
fField->SetTo(&field);
|
||||||
|
|
||||||
|
SendNotices(kUndoRedoChanged);
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SudokuView::Undo()
|
||||||
|
{
|
||||||
|
_UndoRedo(fUndos, fRedos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SudokuView::Redo()
|
||||||
|
{
|
||||||
|
_UndoRedo(fRedos, fUndos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SudokuView::_PushUndo()
|
||||||
|
{
|
||||||
|
fRedos.MakeEmpty();
|
||||||
|
|
||||||
|
BMessage* undo = new BMessage;
|
||||||
|
if (fField->Archive(undo, true) == B_OK
|
||||||
|
&& fUndos.AddItem(undo))
|
||||||
|
SendNotices(kUndoRedoChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SudokuView::MouseDown(BPoint where)
|
SudokuView::MouseDown(BPoint where)
|
||||||
{
|
{
|
||||||
@@ -433,6 +488,7 @@ SudokuView::MouseDown(BPoint where)
|
|||||||
|
|
||||||
uint32 value = hintX + hintY * fBlockSize;
|
uint32 value = hintX + hintY * fBlockSize;
|
||||||
uint32 field = x + y * fField->Size();
|
uint32 field = x + y * fField->Size();
|
||||||
|
_PushUndo();
|
||||||
|
|
||||||
if (clicks == 2 && fLastHintValue == value && fLastField == field
|
if (clicks == 2 && fLastHintValue == value && fLastField == field
|
||||||
|| (buttons & (B_SECONDARY_MOUSE_BUTTON
|
|| (buttons & (B_SECONDARY_MOUSE_BUTTON
|
||||||
@@ -540,6 +596,7 @@ SudokuView::_InsertKey(char rawKey, int32 modifiers)
|
|||||||
if (value == 0)
|
if (value == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_PushUndo();
|
||||||
uint32 hintMask = fField->HintMaskAt(fKeyboardX, fKeyboardY);
|
uint32 hintMask = fField->HintMaskAt(fKeyboardX, fKeyboardY);
|
||||||
uint32 valueMask = 1UL << (value - 1);
|
uint32 valueMask = 1UL << (value - 1);
|
||||||
if (modifiers & B_OPTION_KEY)
|
if (modifiers & B_OPTION_KEY)
|
||||||
@@ -550,6 +607,7 @@ SudokuView::_InsertKey(char rawKey, int32 modifiers)
|
|||||||
fField->SetValueAt(fKeyboardX, fKeyboardY, 0);
|
fField->SetValueAt(fKeyboardX, fKeyboardY, 0);
|
||||||
fField->SetHintMaskAt(fKeyboardX, fKeyboardY, hintMask);
|
fField->SetHintMaskAt(fKeyboardX, fKeyboardY, hintMask);
|
||||||
} else {
|
} else {
|
||||||
|
_PushUndo();
|
||||||
fField->SetValueAt(fKeyboardX, fKeyboardY, value);
|
fField->SetValueAt(fKeyboardX, fKeyboardY, value);
|
||||||
if (value)
|
if (value)
|
||||||
BMessenger(this).SendMessage(kMsgCheckSolved);
|
BMessenger(this).SendMessage(kMsgCheckSolved);
|
||||||
@@ -638,6 +696,14 @@ SudokuView::MessageReceived(BMessage* message)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case B_UNDO:
|
||||||
|
Undo();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_REDO:
|
||||||
|
Redo();
|
||||||
|
break;
|
||||||
|
|
||||||
case kMsgSolveSudoku:
|
case kMsgSolveSudoku:
|
||||||
{
|
{
|
||||||
SudokuSolver solver;
|
SudokuSolver solver;
|
||||||
@@ -647,6 +713,7 @@ SudokuView::MessageReceived(BMessage* message)
|
|||||||
printf("found %ld solutions in %g msecs\n",
|
printf("found %ld solutions in %g msecs\n",
|
||||||
solver.CountSolutions(), (system_time() - start) / 1000.0);
|
solver.CountSolutions(), (system_time() - start) / 1000.0);
|
||||||
if (solver.CountSolutions() > 0) {
|
if (solver.CountSolutions() > 0) {
|
||||||
|
_PushUndo();
|
||||||
fField->SetTo(solver.SolutionAt(0));
|
fField->SetTo(solver.SolutionAt(0));
|
||||||
Invalidate();
|
Invalidate();
|
||||||
} else
|
} else
|
||||||
@@ -668,6 +735,8 @@ SudokuView::MessageReceived(BMessage* message)
|
|||||||
printf("found %ld solutions in %g msecs\n",
|
printf("found %ld solutions in %g msecs\n",
|
||||||
solver.CountSolutions(), (system_time() - start) / 1000.0);
|
solver.CountSolutions(), (system_time() - start) / 1000.0);
|
||||||
if (solver.CountSolutions() > 0) {
|
if (solver.CountSolutions() > 0) {
|
||||||
|
_PushUndo();
|
||||||
|
|
||||||
// find free spot
|
// find free spot
|
||||||
uint32 x, y;
|
uint32 x, y;
|
||||||
do {
|
do {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <View.h>
|
#include <View.h>
|
||||||
|
#include <ObjectList.h>
|
||||||
|
|
||||||
class SudokuField;
|
class SudokuField;
|
||||||
struct entry_ref;
|
struct entry_ref;
|
||||||
@@ -43,6 +44,11 @@ public:
|
|||||||
void SetEditable(bool editable);
|
void SetEditable(bool editable);
|
||||||
bool Editable() const { return fEditable; }
|
bool Editable() const { return fEditable; }
|
||||||
|
|
||||||
|
bool CanUndo() { return !fUndos.IsEmpty(); }
|
||||||
|
bool CanRedo() { return !fRedos.IsEmpty(); }
|
||||||
|
void Undo();
|
||||||
|
void Redo();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void AttachedToWindow();
|
virtual void AttachedToWindow();
|
||||||
|
|
||||||
@@ -75,9 +81,13 @@ private:
|
|||||||
void _FitFont(BFont& font, float width, float height);
|
void _FitFont(BFont& font, float width, float height);
|
||||||
void _DrawKeyboardFocus();
|
void _DrawKeyboardFocus();
|
||||||
void _DrawHints(uint32 x, uint32 y);
|
void _DrawHints(uint32 x, uint32 y);
|
||||||
|
void _UndoRedo(BObjectList<BMessage>& undos, BObjectList<BMessage>& redos);
|
||||||
|
void _PushUndo();
|
||||||
|
|
||||||
rgb_color fBackgroundColor;
|
rgb_color fBackgroundColor;
|
||||||
SudokuField* fField;
|
SudokuField* fField;
|
||||||
|
BObjectList<BMessage> fUndos;
|
||||||
|
BObjectList<BMessage> fRedos;
|
||||||
uint32 fBlockSize;
|
uint32 fBlockSize;
|
||||||
float fWidth, fHeight, fBaseline;
|
float fWidth, fHeight, fBaseline;
|
||||||
BFont fFieldFont;
|
BFont fFieldFont;
|
||||||
@@ -98,4 +108,7 @@ static const uint32 kMsgSudokuSolved = 'susl';
|
|||||||
static const uint32 kMsgSolveSudoku = 'slvs';
|
static const uint32 kMsgSolveSudoku = 'slvs';
|
||||||
static const uint32 kMsgSolveSingle = 'slsg';
|
static const uint32 kMsgSolveSingle = 'slsg';
|
||||||
|
|
||||||
|
// you can observe these:
|
||||||
|
static const int32 kUndoRedoChanged = 'unre';
|
||||||
|
|
||||||
#endif // SUDOKU_VIEW_H
|
#endif // SUDOKU_VIEW_H
|
||||||
|
|||||||
@@ -210,8 +210,7 @@ SudokuWindow::SudokuWindow()
|
|||||||
new BMessage(B_ABOUT_REQUESTED)));
|
new BMessage(B_ABOUT_REQUESTED)));
|
||||||
menu->AddSeparatorItem();
|
menu->AddSeparatorItem();
|
||||||
|
|
||||||
menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED),
|
menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q'));
|
||||||
'Q', B_COMMAND_KEY));
|
|
||||||
menu->SetTargetForItems(this);
|
menu->SetTargetForItems(this);
|
||||||
item->SetTarget(be_app);
|
item->SetTarget(be_app);
|
||||||
menuBar->AddItem(menu);
|
menuBar->AddItem(menu);
|
||||||
@@ -231,8 +230,15 @@ SudokuWindow::SudokuWindow()
|
|||||||
|
|
||||||
// "Help" menu
|
// "Help" menu
|
||||||
menu = new BMenu("Help");
|
menu = new BMenu("Help");
|
||||||
menu->AddItem(new BMenuItem("Store Current", new BMessage(kMsgStoreState)));
|
menu->AddItem(fUndoItem = new BMenuItem("Undo", new BMessage(B_UNDO), 'Z'));
|
||||||
menu->AddItem(fRestoreStateItem = new BMenuItem("Restore Saved",
|
fUndoItem->SetEnabled(false);
|
||||||
|
menu->AddItem(fRedoItem = new BMenuItem("Redo", new BMessage(B_REDO), 'Z',
|
||||||
|
B_SHIFT_KEY));
|
||||||
|
fRedoItem->SetEnabled(false);
|
||||||
|
menu->AddSeparatorItem();
|
||||||
|
|
||||||
|
menu->AddItem(new BMenuItem("Snapshot Current", new BMessage(kMsgStoreState)));
|
||||||
|
menu->AddItem(fRestoreStateItem = new BMenuItem("Restore Snapshot",
|
||||||
new BMessage(kMsgRestoreState)));
|
new BMessage(kMsgRestoreState)));
|
||||||
fRestoreStateItem->SetEnabled(fStoredState != NULL);
|
fRestoreStateItem->SetEnabled(fStoredState != NULL);
|
||||||
menu->AddSeparatorItem();
|
menu->AddSeparatorItem();
|
||||||
@@ -248,6 +254,9 @@ SudokuWindow::SudokuWindow()
|
|||||||
fSavePanel = new BFilePanel(B_SAVE_PANEL);
|
fSavePanel = new BFilePanel(B_SAVE_PANEL);
|
||||||
fSavePanel->SetTarget(this);
|
fSavePanel->SetTarget(this);
|
||||||
|
|
||||||
|
fSudokuView->StartWatching(this, kUndoRedoChanged);
|
||||||
|
// we like to know whenever the undo/redo state changes
|
||||||
|
|
||||||
fProgressWindow = new ProgressWindow(this,
|
fProgressWindow = new ProgressWindow(this,
|
||||||
new BMessage(kMsgAbortSudokuGenerator));
|
new BMessage(kMsgAbortSudokuGenerator));
|
||||||
}
|
}
|
||||||
@@ -499,6 +508,19 @@ SudokuWindow::MessageReceived(BMessage* message)
|
|||||||
B_WIDTH_AS_USUAL, B_IDEA_ALERT))->Go();
|
B_WIDTH_AS_USUAL, B_IDEA_ALERT))->Go();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case B_OBSERVER_NOTICE_CHANGE:
|
||||||
|
{
|
||||||
|
int32 what;
|
||||||
|
if (message->FindInt32(B_OBSERVE_WHAT_CHANGE, &what) != B_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (what == kUndoRedoChanged) {
|
||||||
|
fUndoItem->SetEnabled(fSudokuView->CanUndo());
|
||||||
|
fRedoItem->SetEnabled(fSudokuView->CanRedo());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BWindow::MessageReceived(message);
|
BWindow::MessageReceived(message);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ private:
|
|||||||
SudokuView* fSudokuView;
|
SudokuView* fSudokuView;
|
||||||
GenerateSudoku* fGenerator;
|
GenerateSudoku* fGenerator;
|
||||||
BMenuItem* fRestoreStateItem;
|
BMenuItem* fRestoreStateItem;
|
||||||
|
BMenuItem* fUndoItem;
|
||||||
|
BMenuItem* fRedoItem;
|
||||||
BMessage* fStoredState;
|
BMessage* fStoredState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user