1d578543aSAxel Dörfler/*
250e33476SAxel Dörfler * Copyright 2007-2015, Axel D��rfler, axeld@pinc-software.de.
3d578543aSAxel Dörfler * Distributed under the terms of the MIT License.
4d578543aSAxel Dörfler */
5d578543aSAxel Dörfler
6d578543aSAxel Dörfler
7d578543aSAxel Dörfler#include "SudokuView.h"
8d578543aSAxel Dörfler
9570e1312SFrançois Revol#include "Sudoku.h"
10d578543aSAxel Dörfler#include "SudokuField.h"
11d578543aSAxel Dörfler#include "SudokuSolver.h"
12d578543aSAxel Dörfler
13d578543aSAxel Dörfler#include <ctype.h>
14d578543aSAxel Dörfler#include <errno.h>
15d578543aSAxel Dörfler#include <stdio.h>
16d578543aSAxel Dörfler#include <stdlib.h>
17d578543aSAxel Dörfler
18d578543aSAxel Dörfler#include <Application.h>
19451cbc4aSAxel Dörfler#include <Beep.h>
20bb00cd45SFrançois Revol#include <Bitmap.h>
21bb00cd45SFrançois Revol#include <Clipboard.h>
22fb3fcd87SFrançois Revol#include <DataIO.h>
230abb35c2SFrançois Revol#include <Dragger.h>
24d578543aSAxel Dörfler#include <File.h>
25495bcef7SFrançois Revol#include <NodeInfo.h>
26d578543aSAxel Dörfler#include <Path.h>
27bb00cd45SFrançois Revol#include <Picture.h>
28fb3fcd87SFrançois Revol#include <String.h>
29d578543aSAxel Dörfler
30d578543aSAxel Dörfler
312996f648SAxel Dörflerstatic const uint32 kMsgCheckSolved = 'chks';
32d578543aSAxel Dörfler
332996f648SAxel Dörflerstatic const uint32 kStrongLineSize = 2;
342996f648SAxel Dörfler
352996f648SAxel Dörflerstatic const rgb_color kBackgroundColor = {255, 255, 240};
362996f648SAxel Dörflerstatic const rgb_color kHintColor = {255, 115, 0};
372996f648SAxel Dörflerstatic const rgb_color kValueColor = {0, 91, 162};
382996f648SAxel Dörflerstatic const rgb_color kValueCompletedColor = {55, 140, 35};
392996f648SAxel Dörflerstatic const rgb_color kInvalidValueColor = {200, 0, 0};
402996f648SAxel Dörflerstatic const rgb_color kValueHintBackgroundColor = {255, 215, 127};
412996f648SAxel Dörflerstatic const rgb_color kHintValueHintBackgroundColor = {255, 235, 185};
42d578543aSAxel Dörfler
430abb35c2SFrançois Revolextern const char* kSignature;
440abb35c2SFrançois Revol
45d578543aSAxel Dörfler
46d578543aSAxel DörflerSudokuView::SudokuView(BRect frame, const char* name,
47d578543aSAxel Dörfler		const BMessage& settings, uint32 resizingMode)
48fc64ef86SAxel Dörfler	:
49fc64ef86SAxel Dörfler	BView(frame, name, resizingMode,
500abb35c2SFrançois Revol		B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS)
510abb35c2SFrançois Revol{
52fc64ef86SAxel Dörfler	_InitObject(&settings);
530abb35c2SFrançois Revol
5414cc9629SAxel Dörfler#if 0
550abb35c2SFrançois Revol	BRect rect(Bounds());
560abb35c2SFrançois Revol	rect.top = rect.bottom - 7;
570abb35c2SFrançois Revol	rect.left = rect.right - 7;
5814cc9629SAxel Dörfler	BDragger* dragger = new BDragger(rect, this);
5914cc9629SAxel Dörfler	AddChild(dragger);
6014cc9629SAxel Dörfler#endif
610abb35c2SFrançois Revol}
620abb35c2SFrançois Revol
630abb35c2SFrançois Revol
645ab027fdSAxel DörflerSudokuView::SudokuView(const char* name, const BMessage& settings)
655ab027fdSAxel Dörfler	:
665ab027fdSAxel Dörfler	BView(name,
675ab027fdSAxel Dörfler		B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS)
685ab027fdSAxel Dörfler{
695ab027fdSAxel Dörfler	_InitObject(&settings);
705ab027fdSAxel Dörfler}
715ab027fdSAxel Dörfler
725ab027fdSAxel Dörfler
730abb35c2SFrançois RevolSudokuView::SudokuView(BMessage* archive)
74fc64ef86SAxel Dörfler	:
75fc64ef86SAxel Dörfler	BView(archive)
760abb35c2SFrançois Revol{
77fc64ef86SAxel Dörfler	_InitObject(archive);
780abb35c2SFrançois Revol}
790abb35c2SFrançois Revol
800abb35c2SFrançois Revol
810abb35c2SFrançois RevolSudokuView::~SudokuView()
82d578543aSAxel Dörfler{
830abb35c2SFrançois Revol	delete fField;
840abb35c2SFrançois Revol}
850abb35c2SFrançois Revol
860abb35c2SFrançois Revol
870abb35c2SFrançois Revolstatus_t
887bf86529SFrançois RevolSudokuView::Archive(BMessage* into, bool deep) const
890abb35c2SFrançois Revol{
900abb35c2SFrançois Revol	status_t status;
910abb35c2SFrançois Revol
920abb35c2SFrançois Revol	status = BView::Archive(into, deep);
930abb35c2SFrançois Revol	if (status < B_OK)
940abb35c2SFrançois Revol		return status;
950abb35c2SFrançois Revol
960abb35c2SFrançois Revol	status = into->AddString("add_on", kSignature);
970abb35c2SFrançois Revol	if (status < B_OK)
980abb35c2SFrançois Revol		return status;
990abb35c2SFrançois Revol
1000abb35c2SFrançois Revol	status = into->AddRect("bounds", Bounds());
1010abb35c2SFrançois Revol	if (status < B_OK)
1020abb35c2SFrançois Revol		return status;
1030abb35c2SFrançois Revol
1040abb35c2SFrançois Revol	status = SaveState(*into);
1050abb35c2SFrançois Revol	if (status < B_OK)
1060abb35c2SFrançois Revol		return status;
1070abb35c2SFrançois Revol	return B_OK;
1080abb35c2SFrançois Revol}
1090abb35c2SFrançois Revol
1100abb35c2SFrançois Revol
1110abb35c2SFrançois RevolBArchivable*
1120abb35c2SFrançois RevolSudokuView::Instantiate(BMessage* archive)
1130abb35c2SFrançois Revol{
1140abb35c2SFrançois Revol	if (!validate_instantiation(archive, "SudokuView"))
1150abb35c2SFrançois Revol		return NULL;
1160abb35c2SFrançois Revol	return new SudokuView(archive);
1170abb35c2SFrançois Revol}
1180abb35c2SFrançois Revol
1190abb35c2SFrançois Revol
120d578543aSAxel Dörflerstatus_t
1210abb35c2SFrançois RevolSudokuView::SaveState(BMessage& state) const
122d578543aSAxel Dörfler{
123d578543aSAxel Dörfler	BMessage field;
124d578543aSAxel Dörfler	status_t status = fField->Archive(&field, true);
125d578543aSAxel Dörfler	if (status == B_OK)
126d578543aSAxel Dörfler		status = state.AddMessage("field", &field);
127d578543aSAxel Dörfler	if (status == B_OK)
128d578543aSAxel Dörfler		status = state.AddInt32("hint flags", fHintFlags);
129d578543aSAxel Dörfler	if (status == B_OK)
130d578543aSAxel Dörfler		status = state.AddBool("show cursor", fShowCursor);
131d578543aSAxel Dörfler
132d578543aSAxel Dörfler	return status;
133d578543aSAxel Dörfler}
134d578543aSAxel Dörfler
135d578543aSAxel Dörfler
136d578543aSAxel Dörflerstatus_t
137d578543aSAxel DörflerSudokuView::SetTo(entry_ref& ref)
138d578543aSAxel Dörfler{
139d578543aSAxel Dörfler	BPath path;
140d578543aSAxel Dörfler	status_t status = path.SetTo(&ref);
141d578543aSAxel Dörfler	if (status < B_OK)
142d578543aSAxel Dörfler		return status;
143d578543aSAxel Dörfler
144d578543aSAxel Dörfler	FILE* file = fopen(path.Path(), "r");
145d578543aSAxel Dörfler	if (file == NULL)
146d578543aSAxel Dörfler		return errno;
147d578543aSAxel Dörfler
148d578543aSAxel Dörfler	uint32 maxOut = fField->Size() * fField->Size();
149d578543aSAxel Dörfler	char buffer[1024];
150d578543aSAxel Dörfler	char line[1024];
151d578543aSAxel Dörfler	bool ignore = false;
152d578543aSAxel Dörfler	uint32 out = 0;
153d578543aSAxel Dörfler
154d578543aSAxel Dörfler	while (fgets(line, sizeof(line), file) != NULL
155d578543aSAxel Dörfler		&& out < maxOut) {
156d578543aSAxel Dörfler		status = _FilterString(line, sizeof(line), buffer, out, ignore);
157d578543aSAxel Dörfler		if (status < B_OK) {
158d578543aSAxel Dörfler			fclose(file);
159d578543aSAxel Dörfler			return status;
160d578543aSAxel Dörfler		}
161d578543aSAxel Dörfler	}
162d578543aSAxel Dörfler
1633b54b5c4SAxel Dörfler	_PushUndo();
164d578543aSAxel Dörfler	status = fField->SetTo(_BaseCharacter(), buffer);
165332cc6bcSAxel Dörfler	fValueHintValue = UINT32_MAX;
166d578543aSAxel Dörfler	Invalidate();
167dde69daeSMichael Lotz	fclose(file);
168d578543aSAxel Dörfler	return status;
169d578543aSAxel Dörfler}
170d578543aSAxel Dörfler
171d578543aSAxel Dörfler
172d578543aSAxel Dörflerstatus_t
173d578543aSAxel DörflerSudokuView::SetTo(const char* data)
174d578543aSAxel Dörfler{
175d578543aSAxel Dörfler	if (data == NULL)
176d578543aSAxel Dörfler		return B_BAD_VALUE;
177d578543aSAxel Dörfler
178d578543aSAxel Dörfler	char buffer[1024];
179d578543aSAxel Dörfler	bool ignore = false;
180d578543aSAxel Dörfler	uint32 out = 0;
181d578543aSAxel Dörfler
182d578543aSAxel Dörfler	status_t status = _FilterString(data, 65536, buffer, out, ignore);
183d578543aSAxel Dörfler	if (status < B_OK)
184d578543aSAxel Dörfler		return B_BAD_VALUE;
185d578543aSAxel Dörfler
1863b54b5c4SAxel Dörfler	_PushUndo();
187d578543aSAxel Dörfler	status = fField->SetTo(_BaseCharacter(), buffer);
188332cc6bcSAxel Dörfler	fValueHintValue = UINT32_MAX;
189d578543aSAxel Dörfler	Invalidate();
190d578543aSAxel Dörfler	return status;
191d578543aSAxel Dörfler}
192d578543aSAxel Dörfler
193d578543aSAxel Dörfler
194d578543aSAxel Dörflerstatus_t
195d578543aSAxel DörflerSudokuView::SetTo(SudokuField* field)
196d578543aSAxel Dörfler{
197d578543aSAxel Dörfler	if (field == NULL || field == fField)
198d578543aSAxel Dörfler		return B_BAD_VALUE;
199d578543aSAxel Dörfler
2003b54b5c4SAxel Dörfler	_PushUndo();
201d578543aSAxel Dörfler	delete fField;
202d578543aSAxel Dörfler	fField = field;
203d578543aSAxel Dörfler
204d578543aSAxel Dörfler	fBlockSize = fField->BlockSize();
205332cc6bcSAxel Dörfler	fValueHintValue = UINT32_MAX;
206d578543aSAxel Dörfler	FrameResized(0, 0);
207d578543aSAxel Dörfler	Invalidate();
208d578543aSAxel Dörfler	return B_OK;
209d578543aSAxel Dörfler}
210d578543aSAxel Dörfler
211d578543aSAxel Dörfler
212d578543aSAxel Dörflerstatus_t
21314cc9629SAxel DörflerSudokuView::SaveTo(entry_ref& ref, uint32 exportAs)
214d578543aSAxel Dörfler{
215d578543aSAxel Dörfler	BFile file;
216d578543aSAxel Dörfler	status_t status = file.SetTo(&ref, B_WRITE_ONLY | B_CREATE_FILE
217d578543aSAxel Dörfler		| B_ERASE_FILE);
218d578543aSAxel Dörfler	if (status < B_OK)
219d578543aSAxel Dörfler		return status;
220d578543aSAxel Dörfler
22114cc9629SAxel Dörfler	return SaveTo(file, exportAs);
222dc6e60ecSFrançois Revol}
223d578543aSAxel Dörfler
224d578543aSAxel Dörfler
225dc6e60ecSFrançois Revolstatus_t
22614cc9629SAxel DörflerSudokuView::SaveTo(BDataIO& stream, uint32 exportAs)
227dc6e60ecSFrançois Revol{
22814cc9629SAxel Dörfler	BFile* file = dynamic_cast<BFile*>(&stream);
229dc6e60ecSFrançois Revol	uint32 i = 0;
230495bcef7SFrançois Revol	BNodeInfo nodeInfo;
231495bcef7SFrançois Revol
232495bcef7SFrançois Revol	if (file)
233495bcef7SFrançois Revol		nodeInfo.SetTo(file);
234dc6e60ecSFrançois Revol
23514cc9629SAxel Dörfler	switch (exportAs) {
236bb00cd45SFrançois Revol		case kExportAsText:
23714cc9629SAxel Dörfler		{
23814cc9629SAxel Dörfler			BString text = "# Written by Sudoku\n\n";
239bb00cd45SFrançois Revol			stream.Write(text.String(), text.Length());
240bb00cd45SFrançois Revol
24114cc9629SAxel Dörfler			char* line = text.LockBuffer(1024);
242bb00cd45SFrançois Revol			memset(line, 0, 1024);
243bb00cd45SFrançois Revol			for (uint32 y = 0; y < fField->Size(); y++) {
244bb00cd45SFrançois Revol				for (uint32 x = 0; x < fField->Size(); x++) {
245bb00cd45SFrançois Revol					if (x != 0 && x % fBlockSize == 0)
246bb00cd45SFrançois Revol						line[i++] = ' ';
247bb00cd45SFrançois Revol					_SetText(&line[i++], fField->ValueAt(x, y));
248bb00cd45SFrançois Revol				}
249bb00cd45SFrançois Revol				line[i++] = '\n';
250d578543aSAxel Dörfler			}
251bb00cd45SFrançois Revol			text.UnlockBuffer();
252bb00cd45SFrançois Revol
253bb00cd45SFrançois Revol			stream.Write(text.String(), text.Length());
254bb00cd45SFrançois Revol			if (file)
255bb00cd45SFrançois Revol				nodeInfo.SetType("text/plain");
256bb00cd45SFrançois Revol			return B_OK;
25714cc9629SAxel Dörfler		}
25814cc9629SAxel Dörfler
259bb00cd45SFrançois Revol		case kExportAsHTML:
260bb00cd45SFrançois Revol		{
261bb00cd45SFrançois Revol			bool netPositiveFriendly = false;
26214cc9629SAxel Dörfler			BString text = "<html>\n<head>\n<!-- Written by Sudoku -->\n"
263bb00cd45SFrançois Revol				"<style type=\"text/css\">\n"
26414cc9629SAxel Dörfler				"table.sudoku { background: #000000; border:0; border-collapse: "
26514cc9629SAxel Dörfler					"collapse; cellpadding: 10px; cellspacing: 10px; width: "
26614cc9629SAxel Dörfler					"300px; height: 300px; }\n"
26714cc9629SAxel Dörfler				"td.sudoku { background: #ffffff; border-color: black; "
26814cc9629SAxel Dörfler					"border-left: none ; border-top: none ; /*border: none;*/ "
26914cc9629SAxel Dörfler					"text-align: center; }\n"
270bb00cd45SFrançois Revol				"td.sudoku_initial {  }\n"
271bb00cd45SFrançois Revol				"td.sudoku_filled { color: blue; }\n"
27214cc9629SAxel Dörfler				"td.sudoku_empty {  }\n";
27314cc9629SAxel Dörfler
27414cc9629SAxel Dörfler			// border styles: right bottom (none, small or large)
27514cc9629SAxel Dörfler			const char* kStyles[] = {"none", "small", "large"};
27614cc9629SAxel Dörfler			const char* kCssStyles[] = {"none", "solid 1px black",
27714cc9629SAxel Dörfler				"solid 3px black"};
27814cc9629SAxel Dörfler			enum style_type { kNone = 0, kSmall, kLarge };
27914cc9629SAxel Dörfler
28014cc9629SAxel Dörfler			for (int32 right = 0; right < 3; right++) {
28114cc9629SAxel Dörfler				for (int32 bottom = 0; bottom < 3; bottom++) {
28214cc9629SAxel Dörfler					text << "td.sudoku_";
28314cc9629SAxel Dörfler					if (right != bottom)
28414cc9629SAxel Dörfler						text << kStyles[right] << "_" << kStyles[bottom];
28514cc9629SAxel Dörfler					else
28614cc9629SAxel Dörfler						text << kStyles[right];
28714cc9629SAxel Dörfler
28814cc9629SAxel Dörfler					text << " { border-right: " << kCssStyles[right]
28914cc9629SAxel Dörfler						<< "; border-bottom: " << kCssStyles[bottom] << "; }\n";
29014cc9629SAxel Dörfler				}
29114cc9629SAxel Dörfler			}
29214cc9629SAxel Dörfler
29314cc9629SAxel Dörfler			text << "</style>\n"
294bb00cd45SFrançois Revol				"</head>\n<body>\n\n";
295bb00cd45SFrançois Revol			stream.Write(text.String(), text.Length());
296bb00cd45SFrançois Revol
297bb00cd45SFrançois Revol			text = "<table";
298bb00cd45SFrançois Revol			if (netPositiveFriendly)
29914cc9629SAxel Dörfler				text << " border=\"1\"";
300bb00cd45SFrançois Revol			text << " class=\"sudoku\">";
301bb00cd45SFrançois Revol			stream.Write(text.String(), text.Length());
302bb00cd45SFrançois Revol
303bb00cd45SFrançois Revol			text = "";
304bb00cd45SFrançois Revol			BString divider;
305bb00cd45SFrançois Revol			divider << (int)(100.0 / fField->Size()) << "%";
306bb00cd45SFrançois Revol			for (uint32 y = 0; y < fField->Size(); y++) {
307bb00cd45SFrançois Revol				text << "<tr height=\"" << divider << "\">\n";
308bb00cd45SFrançois Revol				for (uint32 x = 0; x < fField->Size(); x++) {
309bb00cd45SFrançois Revol					char buff[2];
310bb00cd45SFrançois Revol					_SetText(buff, fField->ValueAt(x, y));
311bb00cd45SFrançois Revol
31214cc9629SAxel Dörfler					BString style = "sudoku_";
31314cc9629SAxel Dörfler					style_type right = kSmall;
31414cc9629SAxel Dörfler					style_type bottom = kSmall;
31514cc9629SAxel Dörfler					if ((x + 1) % fField->BlockSize() == 0)
31614cc9629SAxel Dörfler						right = kLarge;
31714cc9629SAxel Dörfler					if ((y + 1) % fField->BlockSize() == 0)
31814cc9629SAxel Dörfler						bottom = kLarge;
319bb00cd45SFrançois Revol					if (x == fField->Size() - 1)
32014cc9629SAxel Dörfler						right = kNone;
321bb00cd45SFrançois Revol					if (y == fField->Size() - 1)
32214cc9629SAxel Dörfler						bottom = kNone;
32314cc9629SAxel Dörfler
32414cc9629SAxel Dörfler					if (right != bottom)
32514cc9629SAxel Dörfler						style << kStyles[right] << "_" << kStyles[bottom];
32614cc9629SAxel Dörfler					else
32714cc9629SAxel Dörfler						style << kStyles[right];
328bb00cd45SFrançois Revol
329bb00cd45SFrançois Revol					if (fField->ValueAt(x, y) == 0) {
330bb00cd45SFrançois Revol						text << "<td width=\"" << divider << "\" ";
33114cc9629SAxel Dörfler						text << "class=\"sudoku sudoku_empty " << style;
33214cc9629SAxel Dörfler						text << "\">\n&nbsp;";
3332996f648SAxel Dörfler					} else if (fField->IsInitialValue(x, y)) {
334bb00cd45SFrançois Revol						text << "<td width=\"" << divider << "\" ";
33514cc9629SAxel Dörfler						text << "class=\"sudoku sudoku_initial " << style
33614cc9629SAxel Dörfler							<< "\">\n";
337bb00cd45SFrançois Revol						if (netPositiveFriendly)
338bb00cd45SFrançois Revol							text << "<font color=\"#000000\">";
339bb00cd45SFrançois Revol						text << buff;
340bb00cd45SFrançois Revol						if (netPositiveFriendly)
341bb00cd45SFrançois Revol							text << "</font>";
342bb00cd45SFrançois Revol					} else {
343bb00cd45SFrançois Revol						text << "<td width=\"" << divider << "\" ";
34414cc9629SAxel Dörfler						text << "class=\"sudoku sudoku_filled sudoku_" << style
34514cc9629SAxel Dörfler							<< "\">\n";
346bb00cd45SFrançois Revol						if (netPositiveFriendly)
347bb00cd45SFrançois Revol							text << "<font color=\"#0000ff\">";
348bb00cd45SFrançois Revol						text << buff;
349bb00cd45SFrançois Revol						if (netPositiveFriendly)
350bb00cd45SFrançois Revol							text << "</font>";
351bb00cd45SFrançois Revol					}
352bb00cd45SFrançois Revol					text << "</td>\n";
353dc6e60ecSFrançois Revol				}
354bb00cd45SFrançois Revol				text << "</tr>\n";
355dc6e60ecSFrançois Revol			}
356bb00cd45SFrançois Revol			text << "</table>\n\n";
357bb00cd45SFrançois Revol
358bb00cd45SFrançois Revol			stream.Write(text.String(), text.Length());
359bb00cd45SFrançois Revol			text = "</body></html>\n";
360bb00cd45SFrançois Revol			stream.Write(text.String(), text.Length());
361bb00cd45SFrançois Revol			if (file)
362bb00cd45SFrançois Revol				nodeInfo.SetType("text/html");
363bb00cd45SFrançois Revol			return B_OK;
364dc6e60ecSFrançois Revol		}
36514cc9629SAxel Dörfler
366bb00cd45SFrançois Revol		case kExportAsBitmap:
367bb00cd45SFrançois Revol		{
36814cc9629SAxel Dörfler			BMallocIO mallocIO;
36914cc9629SAxel Dörfler			status_t status = SaveTo(mallocIO, kExportAsPicture);
370bb00cd45SFrançois Revol			if (status < B_OK)
371bb00cd45SFrançois Revol				return status;
37214cc9629SAxel Dörfler
37314cc9629SAxel Dörfler			mallocIO.Seek(0LL, SEEK_SET);
374bb00cd45SFrançois Revol			BPicture picture;
37514cc9629SAxel Dörfler			status = picture.Unflatten(&mallocIO);
376bb00cd45SFrançois Revol			if (status < B_OK)
377bb00cd45SFrançois Revol				return status;
37814cc9629SAxel Dörfler
37914cc9629SAxel Dörfler			BBitmap* bitmap = new BBitmap(Bounds(), B_BITMAP_ACCEPTS_VIEWS,
38014cc9629SAxel Dörfler				B_RGB32);
38114cc9629SAxel Dörfler			BView* view = new BView(Bounds(), "bitmap", B_FOLLOW_NONE,
38214cc9629SAxel Dörfler				B_WILL_DRAW);
383bb00cd45SFrançois Revol			bitmap->AddChild(view);
38414cc9629SAxel Dörfler
385bb00cd45SFrançois Revol			if (bitmap->Lock()) {
386bb00cd45SFrançois Revol				view->DrawPicture(&picture);
387bb00cd45SFrançois Revol				view->Sync();
38814cc9629SAxel Dörfler
389bb00cd45SFrançois Revol				view->RemoveSelf();
390bb00cd45SFrançois Revol				delete view;
39114cc9629SAxel Dörfler					// it should not become part of the archive
392bb00cd45SFrançois Revol				bitmap->Unlock();
393bb00cd45SFrançois Revol			}
39414cc9629SAxel Dörfler
39514cc9629SAxel Dörfler			BMessage archive;
39614cc9629SAxel Dörfler			status = bitmap->Archive(&archive);
39714cc9629SAxel Dörfler			if (status >= B_OK)
39814cc9629SAxel Dörfler				status = archive.Flatten(&stream);
39914cc9629SAxel Dörfler
400bb00cd45SFrançois Revol			delete bitmap;
401bb00cd45SFrançois Revol			return status;
402bb00cd45SFrançois Revol		}
40314cc9629SAxel Dörfler
404bb00cd45SFrançois Revol		case kExportAsPicture:
405bb00cd45SFrançois Revol		{
406bb00cd45SFrançois Revol			BPicture picture;
407bb00cd45SFrançois Revol			BeginPicture(&picture);
408bb00cd45SFrançois Revol			Draw(Bounds());
40914cc9629SAxel Dörfler
41014cc9629SAxel Dörfler			status_t status = B_ERROR;
41114cc9629SAxel Dörfler			if (EndPicture())
412bb00cd45SFrançois Revol				status = picture.Flatten(&stream);
41314cc9629SAxel Dörfler
414bb00cd45SFrançois Revol			return status;
415bb00cd45SFrançois Revol		}
41614cc9629SAxel Dörfler
417bb00cd45SFrançois Revol		default:
41814cc9629SAxel Dörfler			return B_BAD_VALUE;
419d578543aSAxel Dörfler	}
420d578543aSAxel Dörfler}
421d578543aSAxel Dörfler
422d578543aSAxel Dörfler
423dc6e60ecSFrançois Revolstatus_t
424dc6e60ecSFrançois RevolSudokuView::CopyToClipboard()
425dc6e60ecSFrançois Revol{
426ef0522d2SStephan Aßmus	if (!be_clipboard->Lock())
427fd43517bSAxel Dörfler		return B_ERROR;
428bb00cd45SFrançois Revol
429ef0522d2SStephan Aßmus	be_clipboard->Clear();
430ef0522d2SStephan Aßmus
431ef0522d2SStephan Aßmus	BMessage* clip = be_clipboard->Data();
432ef0522d2SStephan Aßmus	if (clip == NULL) {
433bb00cd45SFrançois Revol		be_clipboard->Unlock();
434fd43517bSAxel Dörfler		return B_ERROR;
435bb00cd45SFrançois Revol	}
436ef0522d2SStephan Aßmus
437ef0522d2SStephan Aßmus	// As BBitmap
438fd43517bSAxel Dörfler	BMallocIO mallocIO;
439fd43517bSAxel Dörfler	status_t status = SaveTo(mallocIO, kExportAsBitmap);
440ef0522d2SStephan Aßmus	if (status >= B_OK) {
441fd43517bSAxel Dörfler		mallocIO.Seek(0LL, SEEK_SET);
442ef0522d2SStephan Aßmus		// ShowImage, ArtPaint & WonderBrush use that
443ef0522d2SStephan Aßmus		status = clip->AddData("image/bitmap", B_MESSAGE_TYPE,
444fd43517bSAxel Dörfler			mallocIO.Buffer(), mallocIO.BufferLength());
445ef0522d2SStephan Aßmus		// Becasso uses that ?
446fd43517bSAxel Dörfler		clip->AddData("image/x-be-bitmap", B_MESSAGE_TYPE, mallocIO.Buffer(),
447fd43517bSAxel Dörfler			mallocIO.BufferLength());
448ef0522d2SStephan Aßmus		// Gobe Productive uses that...
449ef0522d2SStephan Aßmus		// QuickRes as well, with a rect field.
450fd43517bSAxel Dörfler		clip->AddData("image/x-vnd.Be-bitmap", B_MESSAGE_TYPE,
451fd43517bSAxel Dörfler			mallocIO.Buffer(), mallocIO.BufferLength());
452ef0522d2SStephan Aßmus	}
453fd43517bSAxel Dörfler	mallocIO.Seek(0LL, SEEK_SET);
454fd43517bSAxel Dörfler	mallocIO.SetSize(0LL);
455ef0522d2SStephan Aßmus
456ef0522d2SStephan Aßmus	// As HTML
457ef0522d2SStephan Aßmus	if (status >= B_OK)
458fd43517bSAxel Dörfler		status = SaveTo(mallocIO, kExportAsHTML);
459ef0522d2SStephan Aßmus	if (status >= B_OK) {
460fd43517bSAxel Dörfler		status = clip->AddData("text/html", B_MIME_TYPE, mallocIO.Buffer(),
461fd43517bSAxel Dörfler			mallocIO.BufferLength());
462ef0522d2SStephan Aßmus	}
463fd43517bSAxel Dörfler	mallocIO.Seek(0LL, SEEK_SET);
464fd43517bSAxel Dörfler	mallocIO.SetSize(0LL);
465ef0522d2SStephan Aßmus
466ef0522d2SStephan Aßmus	// As plain text
467ef0522d2SStephan Aßmus	if (status >= B_OK)
468fd43517bSAxel Dörfler		SaveTo(mallocIO, kExportAsText);
469ef0522d2SStephan Aßmus	if (status >= B_OK) {
470fd43517bSAxel Dörfler		status = clip->AddData("text/plain", B_MIME_TYPE, mallocIO.Buffer(),
471fd43517bSAxel Dörfler			mallocIO.BufferLength());
472ef0522d2SStephan Aßmus	}
473fd43517bSAxel Dörfler	mallocIO.Seek(0LL, SEEK_SET);
474fd43517bSAxel Dörfler	mallocIO.SetSize(0LL);
475ef0522d2SStephan Aßmus
476fd43517bSAxel Dörfler	// As flattened BPicture, anyone handles that?
477ef0522d2SStephan Aßmus	if (status >= B_OK)
478fd43517bSAxel Dörfler		status = SaveTo(mallocIO, kExportAsPicture);
479ef0522d2SStephan Aßmus	if (status >= B_OK) {
480ef0522d2SStephan Aßmus		status = clip->AddData("image/x-vnd.Be-picture", B_MIME_TYPE,
481fd43517bSAxel Dörfler			mallocIO.Buffer(), mallocIO.BufferLength());
482ef0522d2SStephan Aßmus	}
483fd43517bSAxel Dörfler	mallocIO.SetSize(0LL);
484ef0522d2SStephan Aßmus
485ef0522d2SStephan Aßmus	be_clipboard->Commit();
486ef0522d2SStephan Aßmus	be_clipboard->Unlock();
487ef0522d2SStephan Aßmus
488dc6e60ecSFrançois Revol	return status;
489dc6e60ecSFrançois Revol}
490dc6e60ecSFrançois Revol
491dc6e60ecSFrançois Revol
492d578543aSAxel Dörflervoid
493d578543aSAxel DörflerSudokuView::ClearChanged()
494d578543aSAxel Dörfler{
4953b54b5c4SAxel Dörfler	_PushUndo();
4963b54b5c4SAxel Dörfler
497d578543aSAxel Dörfler	for (uint32 y = 0; y < fField->Size(); y++) {
498d578543aSAxel Dörfler		for (uint32 x = 0; x < fField->Size(); x++) {
4992996f648SAxel Dörfler			if (!fField->IsInitialValue(x, y))
500d578543aSAxel Dörfler				fField->SetValueAt(x, y, 0);
501d578543aSAxel Dörfler		}
502d578543aSAxel Dörfler	}
503d578543aSAxel Dörfler
504d578543aSAxel Dörfler	Invalidate();
505d578543aSAxel Dörfler}
506d578543aSAxel Dörfler
507d578543aSAxel Dörfler
508d578543aSAxel Dörflervoid
509d578543aSAxel DörflerSudokuView::ClearAll()
510d578543aSAxel Dörfler{
5113b54b5c4SAxel Dörfler	_PushUndo();
512d578543aSAxel Dörfler	fField->Reset();
513d578543aSAxel Dörfler	Invalidate();
514d578543aSAxel Dörfler}
515d578543aSAxel Dörfler
516d578543aSAxel Dörfler
517d578543aSAxel Dörflervoid
518d578543aSAxel DörflerSudokuView::SetHintFlags(uint32 flags)
519d578543aSAxel Dörfler{
520d578543aSAxel Dörfler	if (flags == fHintFlags)
521d578543aSAxel Dörfler		return;
522d578543aSAxel Dörfler
523d578543aSAxel Dörfler	if ((flags & kMarkInvalid) ^ (fHintFlags & kMarkInvalid))
524d578543aSAxel Dörfler		Invalidate();
525d578543aSAxel Dörfler
526d578543aSAxel Dörfler	fHintFlags = flags;
527d578543aSAxel Dörfler}
528d578543aSAxel Dörfler
529d578543aSAxel Dörfler
530d578543aSAxel Dörflervoid
531d578543aSAxel DörflerSudokuView::SetEditable(bool editable)
532d578543aSAxel Dörfler{
533d578543aSAxel Dörfler	fEditable = editable;
534d578543aSAxel Dörfler}
535d578543aSAxel Dörfler
536d578543aSAxel Dörfler
537d578543aSAxel Dörflervoid
538fc64ef86SAxel DörflerSudokuView::Undo()
539d578543aSAxel Dörfler{
540fc64ef86SAxel Dörfler	_UndoRedo(fUndos, fRedos);
541d578543aSAxel Dörfler}
542d578543aSAxel Dörfler
543d578543aSAxel Dörfler
544d578543aSAxel Dörflervoid
545fc64ef86SAxel DörflerSudokuView::Redo()
546d578543aSAxel Dörfler{
547fc64ef86SAxel Dörfler	_UndoRedo(fRedos, fUndos);
548fc64ef86SAxel Dörfler}
549d578543aSAxel Dörfler
550d578543aSAxel Dörfler
551fc64ef86SAxel Dörfler// #pragma mark - BWindow methods
552d578543aSAxel Dörfler
553fc64ef86SAxel Dörfler
554fc64ef86SAxel Dörflervoid
555fc64ef86SAxel DörflerSudokuView::AttachedToWindow()
556fc64ef86SAxel Dörfler{
557fc64ef86SAxel Dörfler	MakeFocus(true);
558d578543aSAxel Dörfler}
559d578543aSAxel Dörfler
560d578543aSAxel Dörfler
561d578543aSAxel Dörflervoid
562d578543aSAxel DörflerSudokuView::FrameResized(float /*width*/, float /*height*/)
563d578543aSAxel Dörfler{
564d578543aSAxel Dörfler	// font for numbers
565d578543aSAxel Dörfler
566d578543aSAxel Dörfler	uint32 size = fField->Size();
5672996f648SAxel Dörfler	fWidth = (Bounds().Width() + 2 - kStrongLineSize * (fBlockSize - 1)) / size;
5682996f648SAxel Dörfler	fHeight = (Bounds().Height() + 2 - kStrongLineSize * (fBlockSize - 1))
5692996f648SAxel Dörfler		/ size;
570d578543aSAxel Dörfler	_FitFont(fFieldFont, fWidth - 2, fHeight - 2);
571d578543aSAxel Dörfler
572d578543aSAxel Dörfler	font_height fontHeight;
573d578543aSAxel Dörfler	fFieldFont.GetHeight(&fontHeight);
574d578543aSAxel Dörfler	fBaseline = ceilf(fontHeight.ascent) / 2
575d578543aSAxel Dörfler		+ (fHeight - ceilf(fontHeight.descent)) / 2;
576d578543aSAxel Dörfler
577d578543aSAxel Dörfler	// font for hint
578d578543aSAxel Dörfler
579d578543aSAxel Dörfler	fHintWidth = (fWidth - 2) / fBlockSize;
580d578543aSAxel Dörfler	fHintHeight = (fHeight - 2) / fBlockSize;
581d578543aSAxel Dörfler	_FitFont(fHintFont, fHintWidth, fHintHeight);
582d578543aSAxel Dörfler
583d578543aSAxel Dörfler	fHintFont.GetHeight(&fontHeight);
584d578543aSAxel Dörfler	fHintBaseline = ceilf(fontHeight.ascent) / 2
585d578543aSAxel Dörfler		+ (fHintHeight - ceilf(fontHeight.descent)) / 2;
586fd43517bSAxel Dörfler
587c09b3a97SFrançois Revol	// fix the dragger's position
588c09b3a97SFrançois Revol	BView *dragger = FindView("_dragger_");
589c09b3a97SFrançois Revol	if (dragger)
590c09b3a97SFrançois Revol		dragger->MoveTo(Bounds().right - 7, Bounds().bottom - 7);
591d578543aSAxel Dörfler}
592d578543aSAxel Dörfler
593d578543aSAxel Dörfler
594fc64ef86SAxel Dörflervoid
595fc64ef86SAxel DörflerSudokuView::MouseDown(BPoint where)
596d578543aSAxel Dörfler{
597fc64ef86SAxel Dörfler	uint32 x, y;
598fc64ef86SAxel Dörfler	if (!fEditable || !_GetFieldFor(where, x, y))
599fc64ef86SAxel Dörfler		return;
600d578543aSAxel Dörfler
601fc64ef86SAxel Dörfler	int32 buttons = B_PRIMARY_MOUSE_BUTTON;
602fc64ef86SAxel Dörfler	int32 clicks = 1;
603fc64ef86SAxel Dörfler	if (Looper() != NULL && Looper()->CurrentMessage() != NULL) {
604fc64ef86SAxel Dörfler		Looper()->CurrentMessage()->FindInt32("buttons", &buttons);
605fc64ef86SAxel Dörfler		Looper()->CurrentMessage()->FindInt32("clicks", &clicks);
606fc64ef86SAxel Dörfler	}
607d578543aSAxel Dörfler
608fc64ef86SAxel Dörfler	if (buttons == B_PRIMARY_MOUSE_BUTTON && clicks == 1) {
609fc64ef86SAxel Dörfler		uint32 value = fField->ValueAt(x, y);
610fc64ef86SAxel Dörfler		if (value != 0) {
611cefd7c49SAxel Dörfler			_SetValueHintValue(value);
612fc64ef86SAxel Dörfler			return;
613fc64ef86SAxel Dörfler		}
614fc64ef86SAxel Dörfler	}
615d578543aSAxel Dörfler
616fc64ef86SAxel Dörfler	uint32 hintX, hintY;
617fc64ef86SAxel Dörfler	if (!_GetHintFieldFor(where, x, y, hintX, hintY))
618fc64ef86SAxel Dörfler		return;
619d578543aSAxel Dörfler
620fc64ef86SAxel Dörfler	uint32 value = hintX + hintY * fBlockSize;
621fc64ef86S