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