Intégration du menu

This commit is contained in:
Jérôme Henry-Barnaudière - GeeHB 2023-12-16 12:09:04 +01:00
parent 390ee9df98
commit 6f729c102b
12 changed files with 1166 additions and 257 deletions

View File

@ -9,6 +9,7 @@ set(SOURCES
src/sudoSolv.cpp
src/shared/bFile.cpp
src/shared/keyboard.cpp
src/shared/menuBar.cpp
src/position.cpp
src/element.cpp
src/tinySquare.cpp

View File

@ -5,18 +5,13 @@ Un petit utilitaire en C++ pour Graph 90+E pour créer, éditer des grilles de S
Cette première version ne contient que l'objet central, sans GUI et permet de valider les différentes méthodes de la classe.
En séquence :
* *load()* - Ouverture du fichier "\\fls0\GRIDS\1.txt".
S'il n'existe pas le système partira avec une grille vide;
* *display()* - Affichage
* *load()* - Ouverture du fichier "\\fls0\\GRIDS\\1.txt". S'il n'existe pas le système partira avec une grille vide;
* *display()* - Affichage
* *edit()* - Edition de la grille. Un appui sur "EXE" sort du mode;
* *findObviousValues()* - Recherche des valeurs triviales (obvious values) : ie. les valeurs évidentes;
Elles sont affichées en bleu
* *findObviousValues()* - Recherche des valeurs triviales (obvious values) : ie. les valeurs évidentes; Elles sont affichées en bleu
* *resolve()* - Recherche d'une solution
~~~c
```c
#define GRID_FILE u"\\\\fls0\\GRIDS\\1.txt"
dclear(C_WHITE);
@ -41,10 +36,7 @@ if (myGame.load((FONTCHARACTER)GRID_FILE)){
getkey();
}
}
~~~
```
Le dossier `GRIDS` contient différentes grilles.
Une grille fait exactement 162 octets.
Une grille fait exactement 162 octets.

View File

@ -1,143 +1,143 @@
//---------------------------------------------------------------------------
//--
//-- consts.h
//--
//-- App. constants
//--
//---------------------------------------------------------------------------
#ifndef __S_SOLVER_CONSTANTS_h__
#define __S_SOLVER_CONSTANTS_h__ 1
#include "shared/casioCalcs.h"
#ifdef DEST_CASIO_CALC
#include <gint/keyboard.h>
#else
#include <iostream>
#include <cstdint> // <stdint.h>
using namespace std;
#endif //
#ifdef __cplusplus
extern "C" {
#endif // #ifdef __cplusplus
// Informations about the grid
//
#define ROW_COUNT 9
#define LINE_COUNT ROW_COUNT
#define INDEX_MIN 0
#define INDEX_MAX (ROW_COUNT * LINE_COUNT - 1)
#define VALUE_MIN 1
#define VALUE_MAX 9
// Files
//
#define VALUE_SEPARATOR ',' // Value separator in files
#define FILE_COMMENTS '#' // Comment lines start with
#ifdef DEST_CASIO_CALC
#define GRID_FOLDER u"\\\\fls0\\GRIDS"
#else
#define GRID_FOLDER "/home/jhb/Nextcloud/personnel/JHB/dev/cpp/sudoSolv/GRIDS"
#endif // #ifdef DEST_CASIO_CALC
#define FILE_LINE_SIZE ROW_COUNT * 2 // (value & separator) * ROW_COUNT
#define FILE_SIZE LINE_COUNT * FILE_LINE_SIZE
// Error codes
//
#define SUDO_NO_ERROR 0
#define SUDO_INVALID_FILENAME 1 // File doesn't exist
#define SUDO_INVALID_FILESIZE 2
#define SUDO_NO_FILENAME 3
#define SUDO_IO_ERROR 4
#define SUDO_INVALID_LINE 11
#define SUDO_INVALID_FORMAT 12
#define SUDO_VALUE_ERROR 13 // The value can't be set at this position
// Display
//
#ifdef DEST_CASIO_CALC
#define DELTA_X 5 // Distance from top left corner
#define DELTA_Y DELTA_X // useless in first version ....
#define BORDER_THICK 2 // Thickness of external border
// Dimensions in pixels
#define SQUARE_SIZE 20
#define INT_SQUARE_SIZE (SQUARE_SIZE - 2 * BORDER_THICK)
#define GRID_SIZE SQUARE_SIZE * ROW_COUNT
#define BORDER_COLOUR C_RGB(10, 19, 23)
#define BK_COLOUR C_RGB(28, 28, 30)
#define TXT_COLOUR C_RGB(8, 8, 8)
#define ORIGINAL_COLOUR C_RGB(30, 15, 14)
#define OBVIOUS_COLOUR BORDER_COLOUR
#define SEL_BK_COLOUR C_RGB(6, 6, 31)
#define SEL_TXT_COLOUR C_WHITE
#endif // #ifdef DEST_CASIO_CALC
// Keyboard
//
// Key codes
//
#ifdef DEST_CASIO_CALC
enum GAME_KEY{
KEY_CODE_F1 = KEY_F1, // !!!
KEY_CODE_F6 = KEY_F6,
KEY_CODE_UP = KEY_UP,
KEY_CODE_DOWN = KEY_DOWN,
KEY_CODE_LEFT = KEY_LEFT,
KEY_CODE_RIGHT = KEY_RIGHT,
KEY_CODE_0 = KEY_0,
KEY_CODE_1 = KEY_1,
KEY_CODE_2 = KEY_2,
KEY_CODE_3 = KEY_3,
KEY_CODE_4 = KEY_4,
KEY_CODE_5 = KEY_5,
KEY_CODE_6 = KEY_6,
KEY_CODE_7 = KEY_7,
KEY_CODE_8 = KEY_8,
KEY_CODE_9 = KEY_9,
KEY_CODE_EXIT = KEY_EXIT,
KEY_CODE_EXE = KEY_EXE
};
#else
enum GAME_KEY{
KEY_CODE_F1 = 'A',
KEY_CODE_F6 = 'F',
KEY_CODE_LEFT = 's',
KEY_CODE_RIGHT = 'f',
KEY_CODE_UP = 'e',
KEY_CODE_DOWN = 'x',
KEY_CODE_0 = '0',
KEY_CODE_1 = '1',
KEY_CODE_2 = '2',
KEY_CODE_3 = '3',
KEY_CODE_4 = '4',
KEY_CODE_5 = '5',
KEY_CODE_6 = '6',
KEY_CODE_7 = '7',
KEY_CODE_8 = '8',
KEY_CODE_9 = '9',
KEY_CODE_EXIT = 'q',
KEY_CODE_EXE = '\13'
};
#endif // #ifdef DEST_CASIO_CALC
#ifdef __cplusplus
}
#endif // #ifdef __cplusplus
#endif // __S_SOLVER_CONSTANTS_h__
// EOF
//---------------------------------------------------------------------------
//--
//-- consts.h
//--
//-- App. constants
//--
//---------------------------------------------------------------------------
#ifndef __S_SOLVER_CONSTANTS_h__
#define __S_SOLVER_CONSTANTS_h__ 1
#include "shared/casioCalcs.h"
#ifdef DEST_CASIO_CALC
#include <gint/keyboard.h>
#else
#include <iostream>
#include <cstdint> // <stdint.h>
using namespace std;
#endif //
#ifdef __cplusplus
extern "C" {
#endif // #ifdef __cplusplus
// Informations about the grid
//
#define ROW_COUNT 9
#define LINE_COUNT ROW_COUNT
#define INDEX_MIN 0
#define INDEX_MAX (ROW_COUNT * LINE_COUNT - 1)
#define VALUE_MIN 1
#define VALUE_MAX 9
// Files
//
#define VALUE_SEPARATOR ',' // Value separator in files
#define FILE_COMMENTS '#' // Comment lines start with
#ifdef DEST_CASIO_CALC
#define GRID_FOLDER u"\\\\fls0\\GRIDS"
#else
#define GRID_FOLDER "/home/jhb/Nextcloud/personnel/JHB/dev/cpp/sudoSolv/GRIDS"
#endif // #ifdef DEST_CASIO_CALC
#define FILE_LINE_SIZE ROW_COUNT * 2 // (value & separator) * ROW_COUNT
#define FILE_SIZE LINE_COUNT * FILE_LINE_SIZE
// Error codes
//
#define SUDO_NO_ERROR 0
#define SUDO_INVALID_FILENAME 1 // File doesn't exist
#define SUDO_INVALID_FILESIZE 2
#define SUDO_NO_FILENAME 3
#define SUDO_IO_ERROR 4
#define SUDO_INVALID_LINE 11
#define SUDO_INVALID_FORMAT 12
#define SUDO_VALUE_ERROR 13 // The value can't be set at this position
// Display
//
#ifdef DEST_CASIO_CALC
#define DELTA_X 5 // Distance from top left corner
#define DELTA_Y DELTA_X // useless in first version ....
#define BORDER_THICK 2 // Thickness of external border
// Dimensions in pixels
#define SQUARE_SIZE 20
#define INT_SQUARE_SIZE (SQUARE_SIZE - 2 * BORDER_THICK)
#define GRID_SIZE SQUARE_SIZE * ROW_COUNT
#define BORDER_COLOUR C_RGB(10, 19, 23)
#define BK_COLOUR C_RGB(28, 28, 30)
#define TXT_COLOUR C_RGB(8, 8, 8)
#define ORIGINAL_COLOUR C_RGB(30, 15, 14)
#define OBVIOUS_COLOUR BORDER_COLOUR
#define SEL_BK_COLOUR C_RGB(6, 6, 31)
#define SEL_TXT_COLOUR C_WHITE
#endif // #ifdef DEST_CASIO_CALC
// Keyboard
//
// Key codes
//
#ifdef DEST_CASIO_CALC
enum GAME_KEY{
KEY_CODE_F1 = KEY_F1, // !!!
KEY_CODE_F6 = KEY_F6,
KEY_CODE_UP = KEY_UP,
KEY_CODE_DOWN = KEY_DOWN,
KEY_CODE_LEFT = KEY_LEFT,
KEY_CODE_RIGHT = KEY_RIGHT,
KEY_CODE_0 = KEY_0,
KEY_CODE_1 = KEY_1,
KEY_CODE_2 = KEY_2,
KEY_CODE_3 = KEY_3,
KEY_CODE_4 = KEY_4,
KEY_CODE_5 = KEY_5,
KEY_CODE_6 = KEY_6,
KEY_CODE_7 = KEY_7,
KEY_CODE_8 = KEY_8,
KEY_CODE_9 = KEY_9,
KEY_CODE_EXIT = KEY_EXIT,
KEY_CODE_EXE = KEY_EXE
};
#else
enum GAME_KEY{
KEY_CODE_F1 = 'A',
KEY_CODE_F6 = 'F',
KEY_CODE_LEFT = 's',
KEY_CODE_RIGHT = 'f',
KEY_CODE_UP = 'e',
KEY_CODE_DOWN = 'x',
KEY_CODE_0 = '0',
KEY_CODE_1 = '1',
KEY_CODE_2 = '2',
KEY_CODE_3 = '3',
KEY_CODE_4 = '4',
KEY_CODE_5 = '5',
KEY_CODE_6 = '6',
KEY_CODE_7 = '7',
KEY_CODE_8 = '8',
KEY_CODE_9 = '9',
KEY_CODE_EXIT = 'q',
KEY_CODE_EXE = '\13'
};
#endif // #ifdef DEST_CASIO_CALC
#ifdef __cplusplus
}
#endif // #ifdef __cplusplus
#endif // __S_SOLVER_CONSTANTS_h__
// EOF

View File

@ -1,54 +1,55 @@
//---------------------------------------------------------------------------
//--
//-- grids.h
//--
//-- Definition of grids object - List of grid files stored on "disk"
//--
//---------------------------------------------------------------------------
#ifndef __S_SOLVER_GRIDS_h__
#define __S_SOLVER_GRIDS_h__ 1
#include "consts.h"
#include "shared/bFile.h"
#include <vector>
using namespace std;
#ifdef __cplusplus
extern "C" {
#endif // #ifdef __cplusplus
class grids{
public:
// Construction
grids(const FONTCHARACTER folder);
// Destruction
~grids(){}
// # files in folder
size_t size();
// Access
bool nextFile(FONTCHARACTER fName);
bool prevFile(FONTCHARACTER fName);
// File management
bool newFileName(FONTCHARACTER folder);
bool deleteFile(); // current
// Members
protected:
vector<int> files_;
int current_; // Current file ID
};
#ifdef __cplusplus
}
#endif // #ifdef __cplusplus
#endif // __S_SOLVER_GRIDS_h__
// EOF
//---------------------------------------------------------------------------
//--
//-- grids.h
//--
//-- Definition of grids object - List of grid files stored on "disk"
//--
//---------------------------------------------------------------------------
#ifndef __S_SOLVER_GRIDS_h__
#define __S_SOLVER_GRIDS_h__ 1
#include "consts.h"
#include "shared/bFile.h"
#include <vector>
using namespace std;
#ifdef __cplusplus
extern "C" {
#endif // #ifdef __cplusplus
class grids{
public:
// Construction
grids(const FONTCHARACTER folder);
// Destruction
~grids(){}
// # files in folder
size_t size();
// Access
void fileName(FONTCHARACTER fName); // current
bool nextFile(FONTCHARACTER fName);
bool prevFile(FONTCHARACTER fName);
// File management
bool newFileName(FONTCHARACTER folder);
bool deleteFile(); // current
// Members
protected:
vector<int> files_;
int current_; // Current file ID
};
#ifdef __cplusplus
}
#endif // #ifdef __cplusplus
#endif // __S_SOLVER_GRIDS_h__
// EOF

48
src/menu.h Normal file
View File

@ -0,0 +1,48 @@
//---------------------------------------------------------------------------
//--
//-- menu.h
//--
//-- Definition menu constants
//--
//---------------------------------------------------------------------------
#ifndef __SUDOKU_S_MENU_h__
#define __SUDOKU_S_MENU_h__ 1
#include "shared/menuBar.h"
// Main menu
//
#define IDS_FILE_SUB "File"
#define IDS_EDIT "Edit"
#define IDS_SOLVER_SUB "Solver"
#define IDS_QUIT "Quit"
#define IDM_EDIT 200
#define IDM_QUIT 400
// "File" menu bar
//
#define IDS_FILE_NEW "New"
#define IDS_FILE_PREV "Previous"
#define IDS_FILE_NEXT "Next"
#define IDS_FILE_SAVE "Save"
#define IDM_FILE_NEW 101
#define IDM_FILE_PREV 102
#define IDM_FILE_NEXT 103
#define IDM_FILE_SAVE 104
// "Solver" menu bar
//
#define IDS_SOLVER_OBVIOUS "Obvious"
#define IDS_SOLVER_FIND "Find"
#define IDM_SOLVER_OBVIOUS 301
#define IDM_SOLVER_FIND 302
#endif // __SUDOKU_S_MENU_h__
// EOF

View File

@ -91,7 +91,7 @@ uint8_t position::backward(uint8_t dec){
void position::decRow(uint8_t dec){
int8_t row(row_);
row-=dec;
index_ = (row < 0)?(line_ * ROW_COUNT - 1):(index_ - dec);
index_ = (row < 0)?((line_ + 1) * ROW_COUNT - 1):(index_ - dec);
_whereAmI();
}

View File

@ -97,8 +97,8 @@ typedef struct __point {
// A simple rect. struct
//
typedef struct __rect{
uint16_t x,y; // top left
uint16_t w, h; // width and height
int x,y; // top left
int w, h; // width and height
} RECT;
#endif // #ifndef __GEE_CASIO_CALCS_h__

View File

@ -1,14 +1,6 @@
//---------------------------------------------------------------------------
//--
//-- File : keyboard.cpp
//--
//-- Author : Jérôme Henry-Barnaudière - GeeHB
//--
//-- Project :
//--
//---------------------------------------------------------------------------
//--
//-- Description:
//-- keyboard.cpp
//--
//-- Implementation of keyboard object
//--
@ -62,6 +54,7 @@ uint keyboard::getKey(){
}
#else
key = getchar();
if (key == 10) key = 0; // CR
mod_ = MOD_NONE;
#endif // #ifdef DEST_CASIO_CALC

View File

@ -1,21 +1,13 @@
//---------------------------------------------------------------------------
//--
//-- File : keyboard.h
//--
//-- Author : Jérôme Henry-Barnaudière - GeeHB
//--
//-- Project :
//--
//---------------------------------------------------------------------------
//--
//-- Description:
//-- keyboard.h
//--
//-- Definition of keyboard object
//--
//---------------------------------------------------------------------------
#ifndef __GEE_TOOLS_KEYBOARD_h__
#define __GEE_TOOLS_KEYBOARD_h__ 1
#ifndef __GEE_TOOLS_KEYBOARD_C_h__
#define __GEE_TOOLS_KEYBOARD_C_h__ 1
#include "casioCalcs.h"
@ -85,6 +77,6 @@ protected:
}
#endif // #ifdef __cplusplus
#endif // __GEE_TOOLS_KEYBOARD_h__
#endif // __GEE_TOOLS_KEYBOARD_C_h__
// EOF

516
src/shared/menuBar.cpp Normal file
View File

@ -0,0 +1,516 @@
//---------------------------------------------------------------------------
//--
//-- menuBar.cpp
//--
//-- Implementation of menuBar object
//--
//---------------------------------------------------------------------------
#include "menuBar.h"
#include <cstdlib>
#include <cstring>
#ifndef DEST_CASIO_CALC
#include <iostream>
using namespace std;
#define KEY_F1 'a'
#define KEY_F6 'y'
#endif // #ifndef DEST_CASIO_CALC
// Construction
//
menuBar::menuBar(){
// Intializes members
visible_ = &current_; // show current bar
rect_ = {0, CASIO_HEIGHT - MENUBAR_DEF_HEIGHT - 1, CASIO_WIDTH, MENUBAR_DEF_HEIGHT};
_clearMenuBar(&current_);
}
// Dimensions
//
bool menuBar::setHeight(uint16_t barHeight){
rect_ = {0, CASIO_HEIGHT - barHeight - 1, CASIO_WIDTH, barHeight};
update();
return true;
}
// Drawings
//
void menuBar::update(){
if (NULL == visible_){
return;
}
RECT anchor = {rect_.x, rect_.y, MENUBAR_DEF_ITEM_WIDTH, rect_.h}; // First item's rect
PMENUITEM item(nullptr);
for (uint8_t index(0); index < MENU_MAX_ITEM_COUNT; index++){
item = visible_->items[index];
#ifdef DEST_CASIO_CALC
_drawItem(&anchor, item);
#else
if (item){
cout << "|" << ((item->state == ITEM_SELECTED)?">" : " ");
cout << item->text;
cout << ((item->state == ITEM_SELECTED)?"<" : " ");
cout << "|";
}
else{
cout << "| |";
}
#endif // DEST_CASIO_CALC
anchor.x += anchor.w; // Next item's position
} // for
#ifdef DEST_CASIO_CALC
dupdate();
#else
cout << endl;
#endif // #ifdef DEST_CASIO_CALC
}
// addItem() : Add an item to the current menu bar
//
// @id : Item ID
// @text : Item text
// @state : Item's initial state
//
// @return : true if the item has been added
//
bool menuBar::addItem(int id, const char* text, int state){
size_t len(0);
if (IDM_SUBMENU == id ||
_findItemByID(&current_, id) || // this ID is already handled
current_.itemCount == (MENU_MAX_ITEM_COUNT - 1) ||
! text || !(len = strlen(text))){
return false;
}
PMENUITEM item = _createItem(id, text, state);
if (item){
// Append to the menu
if (IDM_BACK == id){
current_.items[MENU_MAX_ITEM_COUNT-1] = item;
}
else{
current_.items[current_.itemCount++] = item;
}
// one more item in menu
return true;
}
return false;
}
// addSubMenu() : Add a sub menu
//
// @submenu : menubar corresponding to the new submenu
// @text : Submenu text
//
// @return : true if sub menu is added
//
bool menuBar::addSubMenu(const menuBar* subMenu, const char* text){
size_t len(0);
if (!subMenu ||
current_.itemCount == (MENU_MAX_ITEM_COUNT - 1) ||
! text || !(len = strlen(text))){
return false;
}
// Create a copy of the menu bar
PMENUBAR sub = _copyMenuBar((PMENUBAR)subMenu);
if (NULL == sub){
return false;
}
// Create item
PMENUITEM item = _createItem(IDM_SUBMENU, text, ITEM_DEFAULT);
if (NULL == item){
_freeMenuBar(sub, true);
return false;
}
item->status = ITEM_STATUS_SUBMENU;
item->subMenu = sub;
sub->parent = &current_;
current_.items[current_.itemCount++] = item; // Add an item pointing to the sub menu
return true;
}
/*
// createSubMenu() : Create an empty sub menu
//
// @return : a pointer to the new menu object if created
//
menuBar* menuBar::createSubMenu(){
menuBar* sub(NULL);
if (size() < (MENU_MAX_ITEM_COUNT - 1)){
sub = new menuBar;
}
return sub;
}
*/
// activate() : Activate or deactivate an item
//
// When an item is deactivated, it can't be called by the user
//
// @id : Menu item's ID
// @activated : true if item must be activated
//
// @return : true if activation state changed
//
bool menuBar::activate(int id, bool activated){
PMENUITEM item = _findItemByID(&current_, id);
if (item){
// Found an item with this ID
bool inactive = (item->state == ITEM_INACTIVE);
if (inactive == activated){
item->state = (activated?ITEM_DEFAULT:ITEM_INACTIVE); // change item's state
return true;
}
}
return false;
}
// handleKeyboard() : Handle the keyboard events
//
// @return : MENUACTION struct containing info about item selected b user
//
MENUACTION menuBar::handleKeyboard(){
uint key(0);
uint8_t kID(0);
keyboard kb;
PMENUITEM item(NULL);
MENUACTION ret = {0, ACTION_KEYBOARD};
bool readKeyboard(true);
if (readKeyboard){
key = kb.getKey();
// a menu key pressed ?
if (key >= KEY_F1 && key <= KEY_F6){
kID = (key - KEY_F1);
// Associated item
if (kID < MENU_MAX_ITEM_COUNT &&
(item = visible_->items[kID]) &&
item->state != ITEM_INACTIVE){
// A sub menu ?
if (item->status == ITEM_STATUS_SUBMENU){
if (item->subMenu){
visible_ = (MENUBAR*)item->subMenu; // new "visible" menu
_selectIndex(-1, false, false);
update();
}
}
else{
if (IDM_BACK == item->id){
visible_ = visible_->parent; // Return to previous menu
_selectIndex(-1, false, false);
update();
}
else{
// a selectable item ...
ret.value = item->id;
ret.type = ACTION_MENU;
readKeyboard = false;
// select the item
if (kID != visible_->selIndex){
_selectIndex(kID, true, true);
}
}
}
}
#ifndef DEST_CASIO_CALC
update();
#endif // #ifndef DEST_CASIO_CALC
} // if in [KEY_F1, KEY_F6]
else{
ret.value = key;
ret.type = ACTION_KEYBOARD;
readKeyboard = false;
}
}
return ret;
}
// _clearMenuBar() : Empty a menu bar
//
// @bar : menu bar the clear
//
void menuBar::_clearMenuBar(PMENUBAR bar){
if (bar){
bar->itemCount = 0;
bar->selIndex = -1; // No item is selected
bar->parent = NULL;
memset(bar->items, 0, sizeof(PMENUITEM) * MENU_MAX_ITEM_COUNT);
}
}
// _copyMenuBar() : Make a copy of a menu bar
//
// All contained items and sub menus will be copied.
//
// @source : Pointer to the source or NULL on error
//
// @return : Pointer to the new copy
//
PMENUBAR menuBar::_copyMenuBar(PMENUBAR source){
PMENUBAR bar(NULL);
if (source && (bar = (PMENUBAR)malloc(sizeof(MENUBAR)))){
_clearMenuBar(bar);
bar->itemCount = source->itemCount;
bar->parent = source->parent;
uint8_t maxItem(MENU_MAX_ITEM_COUNT-1);
PMENUITEM sitem, nitem;
for (uint8_t index(0); index < maxItem; index++){
nitem = _copyItem(bar, (sitem = source->items[index]));
bar->items[index] = nitem; // simple item copy
}
// In sub menus last right item is used to return to parent menu
bar->items[MENU_MAX_ITEM_COUNT-1] = _createItem(IDM_BACK, STR_BACK, ITEM_DEFAULT);
}
return bar;
}
// _freeMenuBar() : Free memory used by a bar
//
// @bar : Pointer to the bar to be released
// @freeAll : Free bar as well ?
//
void menuBar::_freeMenuBar(PMENUBAR bar, bool freeAll){
if (bar){
PMENUITEM item(NULL);
for (uint8_t index(0); index < MENU_MAX_ITEM_COUNT; index++){
if ((item = bar->items[index])){
// A submenu ?
if ((item->status & ITEM_STATUS_SUBMENU) && item->subMenu){
_freeMenuBar((PMENUBAR)item->subMenu, true);
}
free(item); // free the item
}
}
if (freeAll){
free(bar); // free the bar
}
}
}
//
// Menu items
//
// _findItemByID() : Find an item in the current bar
//
// @bar : menu bar containing items
// @id : id of the searched item
//
// @return : pointer to the item if found or NULL
//
PMENUITEM menuBar::_findItemByID(PMENUBAR bar, int id){
if (bar){
PMENUITEM item(NULL), sItem(NULL);
for (uint8_t index = 0; index < MENU_MAX_ITEM_COUNT; index++){
if ((item = bar->items[index])){
if (item->status & ITEM_STATUS_SUBMENU){
// in a sub menu ?
if ((sItem = _findItemByID((PMENUBAR)item->subMenu, id))){
return sItem; // Found in a sub menu
}
}
else{
if (item->id == id){
return item; // found
}
}
}
}
} // if (bar)
// not found
return NULL;
}
// _createItem() : creae a new menu item
//
// @id : Item's id
// @text : Menu item text
// @state : Item's initial state
//
// @return : pointer to the new created if valid or NULL
//
PMENUITEM menuBar::_createItem(int id, const char* text, int state){
size_t len(strlen(text));
MENUITEM* item(NULL);
if ((item = (PMENUITEM)malloc(sizeof(MENUITEM)))){
item->id = id;
item->state = state;
item->status = ITEM_STATUS_DEFAULT;
if (len > ITEM_NAME_LEN){
strncpy(item->text, text, ITEM_NAME_LEN);
item->text[ITEM_NAME_LEN] = '\0';
}
else{
strcpy(item->text, text);
}
item->subMenu = NULL;
}
return item;
}
// _copyItem() : Make a copy of an item
//
// @bar : Destination menu bar container
// @source : Pointer to the source item
//
// @return : pointer to the copied item or NULL
//
PMENUITEM menuBar::_copyItem(PMENUBAR bar, PMENUITEM source){
PMENUITEM item(NULL);
if (source && (item = (PMENUITEM)malloc(sizeof(MENUITEM)))){
item->id = source->id;
item->state = source->state;
item->status = source->status;
strcpy(item->text, source->text);;
if (source->status & ITEM_STATUS_SUBMENU){
item->subMenu = _copyMenuBar((PMENUBAR)source->subMenu);
((PMENUBAR)(item->subMenu))->parent = bar; // attach it to the new bar
}
else{
item->subMenu = NULL;
}
}
return item;
}
// _selectIndex() : Select an item by index in the current bar
//
// @index : index of menu item to select or unselect
// if equal to -1, unselect the currently selected item
// @selected : true if item is to be selected
// @redraw : when true, item and previously (un)selected item are drawn in their
// new states
//
// @return : true if item is selected
//
bool menuBar::_selectIndex(int8_t index, bool selected, bool redraw){
int8_t sel;
if (index >= MENU_MAX_ITEM_COUNT ||
index == (sel = getSelectedIndex())){
return false; // Nothing to do
}
if (-1 == index){
index = sel;
selected = false;
}
// Select or unselect an item
if (index >= 0){
// Item
PMENUITEM item = visible_->items[index];
if (NULL == item){
return false;
}
if (selected){
item->state = ITEM_SELECTED;
visible_->selIndex = index;
// unselect prev.
if (-1 != sel && (item = visible_->items[sel])){
item->state = ITEM_UNSELECTED;
}
}
else{
item->state = ITEM_UNSELECTED;
visible_->selIndex = -1;
}
}
// Update screen ?
if (redraw){
RECT anchor = {rect_.x, rect_.y, MENUBAR_DEF_ITEM_WIDTH, rect_.h};
if (-1 != sel){
anchor.x+=(sel * anchor.w);
_drawItem(&anchor, visible_->items[sel]);
}
if (-1 != index){
anchor.x=(index * anchor.w + rect_.x);
_drawItem(&anchor, visible_->items[index]);
}
}
// Done
return true;
}
// _drawItem() : Draw an item
//
// @anchor : Position of the item in screen coordinates
// @item : Pointer to a MENUITEM strcut containing informations about item to draw
//
void menuBar::_drawItem(const RECT* anchor, const MENUITEM* item){
#ifdef DEST_CASIO_CALC
bool selected(false);
// Draw back ground
drect(anchor->x, anchor->y, anchor->x + anchor->w - 1, anchor->y + anchor->h - 1, COLOUR_WHITE);
if (item){
selected = (ITEM_SELECTED == item->state);
// Text
if (item->text){
int x,y, w, h;
dsize(item->text, NULL, &w, &h);
// center text
x = anchor->x + (anchor->w - w) / 2;
y = anchor->y + (anchor->h - h) / 2;
// text too large ?
// draw the text
dtext(x, y, selected?ITEM_COLOUR_SELECTED:((item->state == ITEM_INACTIVE)?ITEM_COLOUR_INACTIVE:ITEM_COLOUR_UNSELECTED), item->text);
}
// frame
if (selected){
dline(anchor->x, anchor->y, anchor->x, anchor->y + anchor->h - 2, COLOUR_BLACK); // Left
dline(anchor->x+1, anchor->y + anchor->h - 1,
anchor->x + anchor->w -1 - ITEM_ROUNDED_DIM, anchor->y + anchor->h - 1, COLOUR_BLACK); // bottom
dline(anchor->x + anchor->w -1 - ITEM_ROUNDED_DIM, anchor->y + anchor->h - 1,
anchor->x + anchor->w - 1, anchor->y + anchor->h - 1 - ITEM_ROUNDED_DIM, COLOUR_BLACK); // bottom
dline(anchor->x + anchor->w - 1, anchor->y,
anchor->x + anchor->w - 1, anchor->y + anchor->h - 1 - ITEM_ROUNDED_DIM, COLOUR_BLACK); // right
}
} // if (item)
if (!selected){
dline(anchor->x, anchor->y, anchor->x + anchor->w -1, anchor->y, COLOUR_BLACK);
}
#endif // #ifdef DEST_CASIO_CALC
}
// EOF

294
src/shared/menuBar.h Normal file
View File

@ -0,0 +1,294 @@
//---------------------------------------------------------------------------
//--
//-- menuBar.h
//--
//-- Definition of menuBar object - A bar of menu (or submenu)
//--
//---------------------------------------------------------------------------
#ifndef __MENU_BAR_h__
#define __MENU_BAR_h__ 1
#include "casioCalcs.h"
#include "keyboard.h"
#define MENU_MAX_ITEM_COUNT 6 // ie. "F" buttons count
// Dimensions in pixels
#define MENUBAR_DEF_HEIGHT 22
#define MENUBAR_DEF_ITEM_WIDTH (CASIO_WIDTH / MENU_MAX_ITEM_COUNT)
#define ITEM_NAME_LEN 10 // Max length of item name
// Item state
//
#define ITEM_DEFAULT 0
#define ITEM_SELECTED 1
#define ITEM_UNSELECTED ITEM_DEFAULT
#define ITEM_INACTIVE 2
// Item status
//
#define ITEM_STATUS_DEFAULT 0
#define ITEM_STATUS_SUBMENU 2 // Open a sub menu on "click"
#define ITEM_STATUS_KEYCODE 3 // item's ID is a key code
// Reserved menu item ID
//
#define IDM_SUBMENU 0xFFFA // This item holds a submenu
#define IDM_BACK 0xFFFB // Return to parent menu
#define STR_BACK "^ back ^"
// item colors
#define ITEM_COLOUR_SELECTED COLOUR_BLUE
#define ITEM_COLOUR_UNSELECTED COLOUR_DK_GREY
#define ITEM_COLOUR_INACTIVE COLOUR_GREY
#define ITEM_ROUNDED_DIM 4
// A single item
//
typedef struct _menuItem{
int id;
int state;
int status;
char text[ITEM_NAME_LEN + 1];
void* subMenu;
} MENUITEM,* PMENUITEM;
// A menu bar
//
typedef struct _menuBar{
uint8_t itemCount;
int8_t selIndex;
_menuBar* parent;
PMENUITEM items[MENU_MAX_ITEM_COUNT];
} MENUBAR, * PMENUBAR;
// Action to perform
//
typedef struct _menuAction{
int value;
uint8_t type;
} MENUACTION;
// Type of actions
//
#define ACTION_MENU 0 // value is a menu ID
#define ACTION_KEYBOARD 1 // value is a keycode
#ifdef __cplusplus
extern "C" {
#endif // #ifdef __cplusplus
// menuBar : A bar of menu (or submenu)
//
class menuBar{
public:
// Construction
menuBar();
// Destruction
~menuBar(){
_freeMenuBar(&current_, false);
}
// setHeight() : change menu bar height
//
// @barHeight : New height in pixels
//
// @return : true if hieght has changed
//
bool setHeight(uint16_t barHeight);
// getRect() : Get bounding rect of current menu bar
//
void getRect(RECT& barRect){
barRect = {rect_.x, rect_.y, rect_.w, rect_.h};
}
// update() : Update the menu bar
//
// All items will be drawn according to their state et status
//
void update();
//
// Items & subBars
//
// size() : count of items or sub menus in the bar
//
// @return : The count of items or sub menus
//
uint8_t size(){
return current_.itemCount;
}
// addSubMenu() : Add a sub menu
//
// @submenu : menubar corresponding to the new submenu
// @text : Submenu text
//
// @return : true if sub menu is added
//
bool addSubMenu(const menuBar* subMenu, const char* text);
// createSubMenu() : Create an empty sub menu
//
// @return : a pointer to the new menu object if created
//
//menuBar* createSubMenu();
// addItem() : Add an item to the current menu bar
//
// @id : Item ID
// @text : Item text
// @state : Item's initial state
//
// @return : true if the item has been added
//
bool addItem(int id, const char* text, int state = ITEM_DEFAULT);
// Selection & activation
//
// selectIndex() : Select an item by index in the current bar
//
// @index : index of menu item to select or unselect
// @selected : true if item is to be selected
//
// @return : true if item is selected
//
bool selectIndex(int8_t index, bool selected = true){
return _selectIndex(index, selected, true); // Redraw items
}
// getSelectedIndex() : Index of selected item in the current bar
//
// @return : Index of item selected or -1 if none
//
int8_t getSelectedIndex(){
return (visible_?visible_->selIndex:current_.selIndex);
}
// activate() : Activate or deactivate an item
//
// When an item is deactivated, it can't be called by the user
//
// @id : Menu item's ID
// @activated : true if item must be activated
//
// @return : true if activation state changed
//
bool activate(int id, bool activated = true);
// Access
//
operator PMENUBAR() const{
return (MENUBAR*)(&current_);
}
// handleKeyboard() : Handle the keyboard events
//
// @return : MENUACTION struct containing info about item selected b user
//
MENUACTION handleKeyboard();
// Internal methods
private:
//
// menu bars
//
// _clearMenuBar() : Empty a menu bar
//
// @bar : menu bar the clear
//
void _clearMenuBar(PMENUBAR bar);
// _copyMenuBar() : Make a copy of a menu bar
//
// All contained items and sub menus will be copied.
//
// @source : Pointer to the source
//
// @return : Pointer to the new copy or NULL on error
//
PMENUBAR _copyMenuBar(PMENUBAR source);
// _freeMenuBar() : Free memory used by a bar
//
// @bar : Pointer to the bar to be released
// @freeAll : Free bar as well ?
//
void _freeMenuBar(PMENUBAR bar, bool freeAll);
//
// menu items management
//
// _findItemByID() : Find an item in the current bar
//
// @bar : menu bar containing items
// @id : id of the searched item
//
// @return : pointer to the item if found or NULL
//
PMENUITEM _findItemByID(PMENUBAR bar, int id);
// _createItem() : creae a new menu item
//
// @id : Item's id
// @text : Menu item text
// @state : Item's initial state
//
// @return : pointer to the new created if valid or NULL
//
PMENUITEM _createItem(int id, const char* text, int state);
// _copyItem() : Make a copy of an item
//
// @bar : Destination menu bar container
// @source : Pointer to the source item
//
// @return : pointer to the copied item or NULL
//
PMENUITEM _copyItem(PMENUBAR bar, PMENUITEM source);
// _selectIndex() : Select an item by index in the current bar
//
// @index : index of menu item to select or unselect
// @selected : true if item is to be selected
// @redraw : when true, item and previously (un)selected item are drawn in their
// new states
//
// @return : true if item is selected
//
bool _selectIndex(int8_t index, bool selected, bool redraw);
// _drawItem() : Draw an item
//
// @anchor : Position of the item in screen coordinates
// @item : Pointer to a MENUITEM strcut containing informations about item to draw
//
void _drawItem(const RECT* anchor, const MENUITEM* item);
// Members
private:
MENUBAR current_; // Active bar
RECT rect_; // Bar position and dims
PMENUBAR visible_; // Visible menu bar
};
#ifdef __cplusplus
}
#endif // #ifdef __cplusplus
#endif // __MENU_BAR_h__
// EOF

View File

@ -1,31 +1,103 @@
#include "sudoku.h"
//---------------------------------------------------------------------------
//--
//-- sudoSolv.cpp
//--
//-- Create, edit, modify and find a solution to a sudoku grid
//--
//-- App. entry point
//--
//---------------------------------------------------------------------------
#include "sudoku.h"
#include "menu.h"
#define GRID_FILE u"\\\\fls0\\GRIDS\\1.txt"
int main(void)
{
dclear(C_WHITE);
sudoku myGame;
if (myGame.load((FONTCHARACTER)GRID_FILE)){
myGame.display();
myGame.edit();
// Any obvious value(s) ?
if (myGame.findObviousValues()){
myGame.display();
getkey();
}
// A solution ?
if (myGame.resolve()){
// yes !!!
myGame.display();
getkey();
}
}
sudoku game;
menuBar menu;
//
// Create menus
//
// "File" sub menu
//menuBar* subMenu = menu.createSubMenu(); // equivalent to new menuBar()
//menuBar* subMenu = new menuBar();
{
menuBar subMenu;
subMenu.addItem(IDM_FILE_NEW, IDS_FILE_NEW);
subMenu.addItem(IDM_FILE_PREV, IDS_FILE_PREV, ITEM_INACTIVE);
subMenu.addItem(IDM_FILE_NEXT, IDS_FILE_NEXT, ITEM_INACTIVE);
subMenu.addItem(IDM_FILE_SAVE, IDS_FILE_SAVE, ITEM_INACTIVE);
menu.addSubMenu(&subMenu, IDS_FILE_SUB);
//delete subMenu; // Don't need sub menu any longer !
}
menu.addItem(IDM_EDIT, IDS_EDIT);
// "Solver" submenu
{
menuBar subMenu;
subMenu.addItem(IDM_SOLVER_OBVIOUS, IDS_SOLVER_OBVIOUS);
subMenu.addItem(IDM_SOLVER_FIND, IDS_SOLVER_FIND);
menu.addSubMenu(&subMenu, IDS_SOLVER_SUB);
//delete subMenu;
}
menu.addItem(IDM_QUIT, IDS_QUIT);
menu.update();
//
// App. main loop
//
bool end(false);
MENUACTION action;
while (!end){
// A menu action ?
action = menu.handleKeyboard();
// from menu ?
if (ACTION_MENU == action.type){
switch (action.value){
case IDM_FILE_NEW:
game.empty();
game.display();
break;
case IDM_EDIT:{
bool modified = game.edit();
break;
}
case IDM_SOLVER_OBVIOUS:
game.findObviousValues();
game.display();
break;
case IDM_SOLVER_FIND:
game.resolve();
game.display();
break;
case IDM_QUIT:
end = true;
break;
default:
break; // ???
}
}
}
#ifdef DEST_CASIO_CALC
//gint_setrestart(1);
gint_osmenu();
#endif // #ifdef DEST_CASIO_CALC
return 1;
}