00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "menu.h"
00022 #include "puzzle.h"
00023 #include "setup.h"
00024 #include "bitmap.h"
00025 #include "commands.h"
00026 #include "list.h"
00027 #include <vdr/i18n.h>
00028 #include <vdr/config.h>
00029 #include <vdr/osdbase.h>
00030 #include <vdr/osd.h>
00031 #include <vdr/font.h>
00032
00033 using namespace SudokuPlugin;
00034 using namespace Sudoku;
00035
00036
00037
00038 #define SUDOKU_LIST "sudoku-list"
00039
00040
00041 #define CELL_SIZE 42
00042 #define CELL_POS(i) ((i) * (CELL_SIZE + 2) + (i)/RDIM * 3 + 5)
00043 #define GRID_SIZE (DIM * (CELL_SIZE + 2) + DIM/RDIM * 3 + 5)
00044
00045
00046 #define TRANS(c,t) tColor(((c) & 0x00FFFFFF) | (0xFF * (100-(t))/100)<<24)
00047 #define GRID_COLOR clrWhite
00048 #define CURSUR_COLOR clrBlue
00049 #define NUMBER_FG clrWhite
00050 #define NUMBER_BG clrBlack
00051 #define ERROR_FG clrWhite
00052 #define ERROR_BG clrRed
00053 #define AMBIG_FG clrWhite
00054 #define AMBIG_BG clrMagenta
00055 #define MARKED_FG clrWhite
00056 #define MARKED_BG 0x006400
00057 #define GIVEN_FG clrBlack
00058 #define GIVEN_BG clrCyan
00059 #define POSSIBLE_FG clrBlack
00060 #define POSSIBLE_BG(n) (((n) % 2) ? clrYellow : 0xFF8C00 )
00061
00062
00063
00064
00065
00066 Menu::Menu(cPlugin* plugin, const SetupData& setup, PuzzleGame*& puzzle) :
00067 cOsdObject(true), plugin(plugin), setup(setup), puzzle(puzzle)
00068 {
00069 if (puzzle == NULL)
00070 puzzle = new PuzzleGame(setup.givens_count, setup.symmetric);
00071 xPos = (720 - GRID_SIZE) / 2;
00072 yPos = (576 - GRID_SIZE) / 2;
00073 osd = NULL;
00074 info = NULL;
00075 infoText = NULL;
00076 new_puzzle_request = false;
00077 maxi_font = cFont::CreateFont(setup.maxi_font, setup.maxi_font_height,
00078 setup.maxi_font_width);
00079 mini_font = cFont::CreateFont(setup.mini_font, setup.mini_font_height,
00080 setup.mini_font_width);
00081 command_menu = NULL;
00082 list_menu = NULL;
00083 setup_menu = NULL;
00084 listfile = AddDirectory(plugin->ConfigDirectory(plugin->Name()), SUDOKU_LIST);
00085 }
00086
00087
00088 Menu::~Menu()
00089 {
00090 delete setup_menu;
00091 delete list_menu;
00092 delete command_menu;
00093 delete maxi_font;
00094 delete mini_font;
00095 delete info;
00096 delete osd;
00097 }
00098
00099
00100 void Menu::Show()
00101 {
00102 int x1 = xPos, y1 = yPos;
00103 int x2 = xPos + GRID_SIZE - 1, y2 = yPos + GRID_SIZE -1;
00104
00105 osd = cOsdProvider::NewOsd(0, 0);
00106 if (osd)
00107 {
00108 tArea area = { x1, y1, x2, y2, 4 };
00109 osd->SetAreas(&area, 1);
00110 paint();
00111 }
00112 }
00113
00114
00115 eOSState Menu::ProcessKey(eKeys key)
00116 {
00117 if (command_menu)
00118 {
00119 eOSState state = command_menu->ProcessKey(key);
00120 if (state == osBack)
00121 {
00122 state = osContinue;
00123 CommandType command = command_menu->get_selected_command();
00124 DELETENULL(command_menu);
00125 if (command)
00126 state = (this->*command)();
00127 if (state == osContinue)
00128 Show();
00129 if (state == osUnknown)
00130 state = osContinue;
00131 }
00132 return state;
00133 }
00134
00135 if (list_menu)
00136 {
00137 eOSState state = list_menu->ProcessKey(key);
00138 if (state == osBack)
00139 {
00140 state = osContinue;
00141 const char* sudoku = list_menu->get_selected_sudoku();
00142 if (sudoku)
00143 puzzle->load_from_dump(sudoku);
00144 DELETENULL(list_menu);
00145 Show();
00146 }
00147 return state;
00148 }
00149
00150 if (setup_menu)
00151 {
00152 eOSState state = setup_menu->ProcessKey(key);
00153 if (state == osBack)
00154 {
00155 state = osContinue;
00156 if (key == kOk)
00157 Setup.Save();
00158 DELETENULL(setup_menu);
00159 DELETENULL(maxi_font);
00160 DELETENULL(mini_font);
00161 maxi_font = cFont::CreateFont(setup.maxi_font, setup.maxi_font_height,
00162 setup.maxi_font_width);
00163 mini_font = cFont::CreateFont(setup.mini_font, setup.mini_font_height,
00164 setup.mini_font_width);
00165 Show();
00166 }
00167 return state;
00168 }
00169
00170 eOSState state = cOsdObject::ProcessKey(key);
00171 if (state == osUnknown)
00172 {
00173 Pos curr = puzzle->get_pos();
00174 CommandType command = NULL;
00175 switch (key)
00176 {
00177 case kLeft:
00178 case kLeft|k_Repeat:
00179 puzzle->set_pos(curr.prev_col());
00180 break;
00181 case kRight:
00182 case kRight|k_Repeat:
00183 puzzle->set_pos(curr.next_col());
00184 break;
00185 case kUp:
00186 case kUp|k_Repeat:
00187 puzzle->set_pos(curr.prev_row());
00188 break;
00189 case kDown:
00190 case kDown|k_Repeat:
00191 puzzle->set_pos(curr.next_row());
00192 break;
00193 case k0:
00194 case k1:
00195 case k2:
00196 case k3:
00197 case k4:
00198 case k5:
00199 case k6:
00200 case k7:
00201 case k8:
00202 case k9:
00203 puzzle->set_with_history(key - k0);
00204 break;
00205 case kRed:
00206 command = CommandList::command(setup.key_red);
00207 break;
00208 case kGreen:
00209 command = CommandList::command(setup.key_green);
00210 break;
00211 case kYellow:
00212 command = CommandList::command(setup.key_yellow);
00213 break;
00214 case kBlue:
00215 osd->Flush();
00216 DELETENULL(osd);
00217 command_menu = new CommandMenu();
00218 command_menu->Display();
00219 return osContinue;
00220 case kOk:
00221 if (new_puzzle_request)
00222 generate();
00223 break;
00224 case kBack:
00225 return exit();
00226 default:
00227 return osContinue;
00228 }
00229 if (command)
00230 {
00231 state = (this->*command)();
00232 if (state == osUnknown)
00233 return osContinue;
00234 if (state == osEnd)
00235 return osEnd;
00236 }
00237 new_puzzle_request = !new_puzzle_request && puzzle->solved();
00238 if (new_puzzle_request)
00239 infoText = tr("Congratulations!\nPress OK to start a new puzzle");
00240 paint();
00241 state = osContinue;
00242 }
00243 return state;
00244 }
00245
00246
00247 eOSState Menu::generate()
00248 {
00249 puzzle->generate(setup.givens_count, setup.symmetric);
00250 return osContinue;
00251 }
00252
00253
00254 eOSState Menu::load()
00255 {
00256 if (osd)
00257 osd->Flush();
00258 DELETENULL(osd);
00259 list_menu = new ListMenu(listfile);
00260 list_menu->Display();
00261 return osUnknown;
00262 }
00263
00264
00265 eOSState Menu::save()
00266 {
00267 if (osd)
00268 osd->Flush();
00269 DELETENULL(osd);
00270 list_menu = new ListMenu(listfile, puzzle->get_dump());
00271 list_menu->Display();
00272 return osUnknown;
00273 }
00274
00275
00276 eOSState Menu::undo()
00277 {
00278 puzzle->backward();
00279 return osContinue;
00280 }
00281
00282
00283 eOSState Menu::redo()
00284 {
00285 puzzle->forward();
00286 return osContinue;
00287 }
00288
00289
00290 eOSState Menu::toggle_mark()
00291 {
00292 puzzle->toggle_mark(puzzle->get_pos());
00293 return osContinue;
00294 }
00295
00296
00297 eOSState Menu::next_cell()
00298 {
00299 Pos new_pos = puzzle->next_cell(puzzle->get_pos());
00300 if (new_pos <= Pos::last())
00301 puzzle->set_pos(new_pos);
00302 return osContinue;
00303 }
00304
00305
00306 eOSState Menu::next_number()
00307 {
00308 puzzle->set_with_history(puzzle->next_number(puzzle->get_pos()));
00309 return osContinue;
00310 }
00311
00312
00313 eOSState Menu::reset()
00314 {
00315 puzzle->reset(setup.clear_marks);
00316 return osContinue;
00317 }
00318
00319
00320 eOSState Menu::open_setup()
00321 {
00322 if (osd)
00323 osd->Flush();
00324 DELETENULL(osd);
00325 setup_menu = plugin->SetupMenu();
00326 setup_menu->SetPlugin(plugin);
00327 setup_menu->Display();
00328 return osUnknown;
00329 }
00330
00331
00332 eOSState Menu::exit()
00333 {
00334 return osEnd;
00335 }
00336
00337
00338 void Menu::paint()
00339 {
00340 int trans = setup.transparency;
00341 tColor fg, bg = TRANS(GRID_COLOR, trans);
00342 int x1 = xPos, y1 = yPos;
00343 int x2 = xPos + GRID_SIZE - 1, y2 = yPos + GRID_SIZE -1;
00344
00345
00346 cPalette savePalette(*osd->GetBitmap(0));
00347 osd->DrawRectangle(x1, y1, x2, y2, bg);
00348 osd->SetPalette(savePalette, 0);
00349
00350
00351 for (Pos p = Pos::first(); p <= Pos::last(); p = p.next())
00352 {
00353 fg = NUMBER_FG, bg = NUMBER_BG;
00354 if (puzzle->given(p))
00355 fg = GIVEN_FG, bg = GIVEN_BG;
00356 else if (puzzle->marked(p))
00357 fg = MARKED_FG, bg = MARKED_BG;
00358 else if (setup.mark_errors && puzzle->error(p))
00359 fg = ERROR_FG, bg = ERROR_BG;
00360 else if (setup.mark_ambiguous && puzzle->ambiguous(p))
00361 fg = AMBIG_FG, bg = AMBIG_BG;
00362 fg = TRANS(fg, trans);
00363 bg = TRANS(bg, trans);
00364
00365
00366 x1 = xPos + CELL_POS(p.col()), y1 = yPos + CELL_POS(p.row());
00367 x2 = x1 + CELL_SIZE - 1, y2 = y1 + CELL_SIZE - 1;
00368 osd->DrawRectangle(x1, y1, x2, y2, bg);
00369
00370
00371 if (puzzle->get(p) != 0)
00372 {
00373 char txt[2] = { '0' + puzzle->get(p), 0 };
00374 osd->DrawText(x1, y1, txt, fg, bg, maxi_font,
00375 CELL_SIZE, CELL_SIZE, taCenter);
00376 }
00377 else if (setup.show_possibles_pattern || setup.show_possibles_digits)
00378 {
00379 for (unsigned int n = 1; n <= DIM; ++n)
00380 {
00381 if (puzzle->possible_number(p, n))
00382 {
00383 int x3 = x1 + (((n - 1) % RDIM) * CELL_SIZE) / RDIM;
00384 int y3 = y1 + (((n - 1) / RDIM) * CELL_SIZE) / RDIM;
00385 int x4 = x1 + (((n - 1) % RDIM + 1) * CELL_SIZE) / RDIM - 1;
00386 int y4 = y1 + (((n - 1) / RDIM + 1) * CELL_SIZE) / RDIM - 1;
00387
00388 if (setup.show_possibles_pattern)
00389 {
00390 fg = TRANS(POSSIBLE_FG, trans);
00391 bg = TRANS(POSSIBLE_BG(n), trans);
00392 osd->DrawRectangle(x3, y3, x4, y4, bg);
00393 }
00394
00395 if (setup.show_possibles_digits)
00396 {
00397 char txt[2] = { '0' + n, 0 };
00398 osd->DrawText(x3, y3, txt, fg, bg, mini_font,
00399 CELL_SIZE / RDIM, CELL_SIZE / RDIM, taCenter);
00400 }
00401 }
00402 }
00403 }
00404 }
00405
00406
00407 Pos curr = puzzle->get_pos();
00408 bg = TRANS(CURSUR_COLOR, trans);
00409 x1 = xPos + CELL_POS(curr.col()), y1 = yPos + CELL_POS(curr.row());
00410 x2 = x1 + CELL_SIZE - 1, y2 = y1 + CELL_SIZE - 1;
00411 osd->DrawRectangle(x1 - 5, y1 - 5, x2, y1, bg);
00412 osd->DrawRectangle(x1 - 5, y1, x1, y2 + 5, bg);
00413 osd->DrawRectangle(x1, y2, x2 + 5, y2 + 5, bg);
00414 osd->DrawRectangle(x2, y1 - 5, x2 + 5, y2, bg);
00415
00416
00417 if (infoText)
00418 {
00419 if (!info)
00420 info = new Bitmap(GRID_SIZE - 20, 90);
00421 info->text(infoText);
00422 osd->DrawBitmap(xPos + 10, yPos + 10, *info);
00423 infoText = NULL;
00424 }
00425
00426 osd->Flush();
00427 }