Сб май 02, 2020 10:33:54
// главное меню
// id name parent prev next func|subm property
MENU_CMD( mm_1, "BEEP", NONE, NONE, mm_2, beep);
MENU_PROP(mm_2, "TEST", NONE, mm_1, mm_3, NULL, PROP_U8(u8, NOSTORE, 0, 12));
MENU_PROP(mm_3, "MOTOR", NONE, mm_2, mm_4, motor, PROP_BOOL(motor_state, NOSTORE, sf("STOP"), sf("RUN")));
MENU_SUB( mm_4, "SUBMENU", NONE, mm_3, mm_5, sm_1);
MENU_PROP(mm_5, "TEMPERATURE", NONE, mm_4, mm_6, NULL, PROP_I16(vfr, NOSTORE, -20, 20));
MENU_CMD( mm_6, "LOAD", NONE, mm_5, mm_7, load);
MENU_CMD( mm_7, "SAVE & EXIT", NONE, mm_6, NONE, save);
// субменю
MENU_CMD( sm_1, "STOP DEMO 1", mm_4, NONE, sm_2, done);
MENU_CMD( sm_2, "STOP DEMO 2", mm_4, sm_1, sm_3, done);
MENU_SUB( sm_3, "STOP SUB", mm_4, sm_2, NONE, ssm_1);
// субменю 2
MENU_CMD(ssm_1, "SUB STOP DEMO 1", sm_3, NONE, ssm_2, done);
MENU_CMD(ssm_2, "SUB STOP DEMO 2", sm_3, ssm_1, ssm_3, done);
MENU_CMD(ssm_3, "SUB STOP DEMO 3", sm_3, ssm_2, NONE, done);
Сб май 02, 2020 13:47:40
Сб май 02, 2020 14:18:16
Сб май 02, 2020 14:36:42
Сб май 02, 2020 17:26:37
Сб май 02, 2020 18:27:18
Вт май 05, 2020 13:07:22
//==================
#ifndef MENU_H
#define MENU_H
#include "menu.h"
#include "main_def_func.h"
//==================
//==================
// Typedefs:
typedef void (*FuncPtr)(void);
//==================
//==================
typedef struct menu_item
{
void *Parent;
void *Child;
void *Next;
void *Prev;
FuncPtr EnterFunc;
FuncPtr PlusFunc;
FuncPtr MinusFunc;
FuncPtr MenuInitFunc;
char __flash *Rus_Text;
char __flash *Angl_Text;
} menu_item;
//==================
// Externs:
//==================
extern menu_item __flash *CurrMenuItem; // Текущий пункт меню.
extern menu_item __flash Null_Menu;
//==================
// Defines and Macros:
//==================
#define NULL_ENTRY Null_Menu
#define NULL_FUNC (void*)0
#define NULL_TEXT ""
#define PAGE_MENU 3
//==================
//==================
#define MAKE_MENU(Name, Parent, Child, Next, Prev, EnterFunc, PlusFunc, MinusFunc, MenuInitFunc, Rus_Text, Angl_Text) \
extern menu_item __flash Parent; \
extern menu_item __flash Child; \
extern menu_item __flash Next; \
extern menu_item __flash Prev; \
menu_item __flash Name = \
{ \
(menu_item*) &Parent, \
(menu_item*) &Child, \
(menu_item*) &Next, \
(menu_item*) &Prev, \
EnterFunc, \
PlusFunc, \
MinusFunc, \
MenuInitFunc, \
{Rus_Text}, \
{Angl_Text} \
}
//==================
//==================
#define PARENT *((menu_item __flash*) (CurrMenuItem->Parent))
#define CHILD *((menu_item __flash*) (CurrMenuItem->Child))
#define NEXT *((menu_item __flash*) (CurrMenuItem->Next))
#define PREV *((menu_item __flash*) (CurrMenuItem->Prev))
#define ENTER_FUNC *((FuncPtr) (CurrMenuItem->EnterFunc))
#define MENU_PLUS_FUNC *((FuncPtr) (CurrMenuItem->PlusFunc))
#define MENU_MINUS_FUNC *((FuncPtr) (CurrMenuItem->MinusFunc))
#define MENU_INIT_FUNC *((FuncPtr) (CurrMenuItem->MenuInitFunc))
//==================
//==================
#define SET_MENU_LEVEL(x) \
Set_Menu_Level(&x)
#define SET_MENU_ITEM(x) \
Set_Menu_Item(&x)
#define GO_MENU_FUNC(x) \
MenuFunc((FuncPtr*)&x)
#define EXTERN_MENU(Name) \
extern menu_item __flash Name;
#define CHK_CHANGE_MENU(x) \
chk_change_menu(&x)
//==================
//==================
enum
{
SET_LEVEL = 0,
SET_NEXT,
SET_PREV,
};
//==================
// Prototypes:
//==================
bool Set_Menu_Level (menu_item __flash *NewMenu);
bool MenuFunc(FuncPtr* Function);
bool chk_change_menu (menu_item __flash *NewMenu);
//==================
//==================
bool proc_menu_keys (void);
//==================
//==================
void Out_Menu_Items_Init (void);
void Out_Menu_Items (void);
//==================
//==================
void out_name_level (void);
u08 count_chars (char __flash *data);
void make_page_menu (void);
void inc_pos_y_curs (void);
void dec_pos_y_curs (void);
void set_pos_curs (void);
//==================
//==================
char __flash * Get_Addr_Lang_Text (void);
//==================
#endif
//==================
#include "menu.h"
//==================
//==================
static u08 quant_items;
static u08 pos_y_curs;
//==================
//================
menu_item __flash *CurrMenuItem; // Текущий пункт меню.
menu_item __flash *BeginCurrMenuLevel; // Начало массива текущего уровня меню.
menu_item __flash *temp_menu;
menu_item __flash Null_Menu = {(void*)0, (void*)0, (void*)0, (void*)0, NULL_FUNC, NULL_FUNC, NULL_FUNC, NULL_FUNC, NULL_TEXT, NULL_TEXT};
//================
//==================
bool Set_Menu_Level (menu_item __flash *NewMenu)
{
if ((void*)NewMenu == (void*)&NULL_ENTRY)
return false;
else
{
CurrMenuItem = NewMenu;
Out_Menu_Items_Init (); // Так как новый уровень, инициализация переменных.
Out_Menu_Items (); // Вывод названия уровня меню и пунктов меню, курсора.
GO_MENU_FUNC (MENU_INIT_FUNC);
return true;
}
}
//==================
//==================
bool MenuFunc (FuncPtr* Function)
{
if ((void*) Function == (void*) NULL_FUNC)
return false;
else
{
((FuncPtr) Function)();
return true;
}
}
//==================
/*
Уровни, пункты, текст - все выводится автоматом.
Так как все переходы по меню расписаны в структуре, то отпадает надобность в запоминании перемещений по меню.
*/
//==================
void Out_Menu_Items_Init (void)
{
quant_items = 1;
pos_y_curs = 1;
// Получение адреса начала массива уровня меню.
BeginCurrMenuLevel = CurrMenuItem;
temp_menu = (menu_item __flash *)(CurrMenuItem->Prev);
while (1)
{
if ((void*)temp_menu == (void*)&NULL_ENTRY)
{
break;
}
else
{
BeginCurrMenuLevel = temp_menu;
temp_menu = (menu_item __flash *)(temp_menu->Prev);
}
}
// Получение количества пунктов меню.
temp_menu = (menu_item __flash *)(BeginCurrMenuLevel->Next);
while (1)
{
if ((void*)temp_menu == (void*)&NULL_ENTRY)
{
break;
}
temp_menu = (menu_item __flash *)(temp_menu->Next);
quant_items++;
}
// Позиция курсора.
if (quant_items > 1)
{
temp_menu = BeginCurrMenuLevel;
while (1)
{
if ((void*)temp_menu == (void*)&NULL_ENTRY)
return;
if (temp_menu == CurrMenuItem)
return;
else
pos_y_curs++;
temp_menu = (menu_item __flash *)(temp_menu->Next);
}
}
}
void Out_Menu_Items (void)
{
clr_dsp_buf ();
out_name_level (); // Вывод названия уровня меню.
make_page_menu (); // Вывод пунктов меню.
set_pos_curs (); // Установка позиции и вывод курсора.
}
//==================
//==================
// Вывод названия уровня меню.
void out_name_level (void)
{
temp_menu = (menu_item __flash *)(CurrMenuItem->Parent); // Считывание названия уровня меню из пункта меню в верхнем уровне.
if ((void*)temp_menu != (void*)&NULL_ENTRY)
{
u08 i = count_chars (Get_Addr_Lang_Text ()); // Подсчет кол-ва символов в строке.
// Выравнивание текста посередине строки дисплея.
u08 a = i;
i = (20 - i); // Дисплей 20x4. Отнимаем от 20 число символов.
i >>= 1; // Делим остаток на 2.
if (a & (1<<0))
i += 2; // Если число нечетное.
else
i++; // Если число четное.
Print_Buf (1, i, Get_Addr_Lang_Text ());
}
}
//==================
//==================
// Подсчет кол-ва символов в строке.
u08 count_chars (char __flash *data)
{
u08 i = 0;
while (data [i])
{
i++;
}
return i;
}
//==================
//==================
void make_page_menu (void)
{
signed char tmp_pos_y_curs;
u08 i; // Счетчик страниц.
u08 j; // Страница меню.
if (quant_items > 1) // Если пунктов меню больше 1, значит есть что выводить.
{
temp_menu = BeginCurrMenuLevel;
if (pos_y_curs > PAGE_MENU)
{
tmp_pos_y_curs = pos_y_curs;
i = 0; // Счетчик страниц.
while (tmp_pos_y_curs > 0)
{
tmp_pos_y_curs -= PAGE_MENU;
i++;
}
tmp_pos_y_curs += PAGE_MENU;
j = PAGE_MENU; // Страница меню.
while (i-- > 1)
{
while (j--)
{
temp_menu = (menu_item __flash *)(temp_menu->Next); // Следующий пункт меню.
}
j = PAGE_MENU; // Страница меню.
}
}
u08 pos_y_text_item = 2; //
j = PAGE_MENU; // Страница меню.
while (j--)
{
Print_Buf (pos_y_text_item, 2, Get_Addr_Lang_Text ()); // вывод названия пункта меню.
temp_menu = (menu_item __flash *)(temp_menu->Next); // Следующий пункт меню.
if ((void*)temp_menu == (void*)&NULL_ENTRY) // Если элемент Next
return; // пустой, то выход.
else
pos_y_text_item++;
}
}
}
//==================
//==================
void inc_pos_y_curs (void)
{
if (quant_items > 1)
{
if (pos_y_curs < quant_items) pos_y_curs++;
}
}
void dec_pos_y_curs (void)
{
if (quant_items > 1)
{
if (pos_y_curs > 1) pos_y_curs--;
}
}
//==================
//==================
void set_pos_curs (void)
{
if (quant_items > 1)
{
signed char tmp = pos_y_curs;
while (tmp > 0)
{
tmp -= PAGE_MENU;
}
if (tmp <= 0) tmp += PAGE_MENU;
Print_Char (tmp + 1, 1, ARROW_RIGHT);
}
}
//==================
//==================
bool chk_change_menu (menu_item __flash *NewMenu)
{
if ((void*)NewMenu == (void*)&NULL_ENTRY)
return false;
else
return true;
}
//==================
//==================
char __flash * Get_Addr_Lang_Text (void)
{
switch (get_lang ())
{
case RUS:
return temp_menu -> Rus_Text;
case ANGL:
return temp_menu -> Angl_Text;
default:
return NULL_TEXT;
}
}
//==================
//==================
#ifndef MENU_H
#define MENU_H
#include "menu.h"
#include "main_def_func.h"
//==================
//==================
// Typedefs:
typedef void (*FuncPtr)(void);
//==================
//==================
typedef struct menu_item
{
void *Parent;
void *Child;
void *Next;
void *Prev;
FuncPtr PlusFunc;
FuncPtr MinusFunc;
FuncPtr EnterFunc;
FuncPtr MenuInitFunc;
char __flash *Text;
} menu_item;
//==================
// Externs:
//==================
extern menu_item __flash *CurrMenuItem; // Текущий пункт меню.
extern menu_item __flash *BeginCurrMenuLevel; // Начало массива текущего уровня меню.
extern __flash menu_item Null_Menu;
extern char Menu_Str_Buf []; // Буфер для вывода текста.
extern void (*MenuFuncPtr)(void);
//==================
// Defines and Macros:
//==================
#define NULL_ENTRY Null_Menu
#define NULL_FUNC (void*)0
#define NULL_TEXT ""
#define PAGE_MENU 3
//==================
//==================
#define MAKE_MENU(Name, Parent, Child, Next, Prev, PlusFunc, MinusFunc, EnterFunc, MenuInitFunc, Text) \
extern menu_item __flash Parent; \
extern menu_item __flash Child; \
extern menu_item __flash Next; \
extern menu_item __flash Prev; \
menu_item __flash Name = \
{ \
(menu_item*) &Parent, \
(menu_item*) &Child, \
(menu_item*) &Next, \
(menu_item*) &Prev, \
PlusFunc, \
MinusFunc, \
EnterFunc, \
MenuInitFunc, \
{Text} \
}
//==================
//==================
#define PARENT *((menu_item __flash*) (CurrMenuItem->Parent))
#define CHILD *((menu_item __flash*) (CurrMenuItem->Child))
#define NEXT *((menu_item __flash*) (CurrMenuItem->Next))
#define PREV *((menu_item __flash*) (CurrMenuItem->Prev))
#define PLUS_FUNC *((FuncPtr) (CurrMenuItem->PlusFunc))
#define MINUS_FUNC *((FuncPtr) (CurrMenuItem->MinusFunc))
#define ENTER_FUNC *((FuncPtr) (CurrMenuItem->EnterFunc))
#define MENU_INIT_FUNC *((FuncPtr) (CurrMenuItem->MenuInitFunc))
//==================
//==================
#define SET_MENU_LEVEL(x) \
Set_Menu_Level(&x)
#define GO_MENU_FUNC(x) \
MenuFunc((FuncPtr*)&x)
#define EXTERN_MENU(Name) \
extern menu_item __flash Name;
//==================
//==================
enum
{
SET_LEVEL = 0,
SET_NEXT,
SET_PREV,
};
//==================
// Prototypes:
//==================
bool Set_Menu_Level (menu_item __flash *NewMenu);
bool MenuFunc(FuncPtr* Function);
//==================
//==================
void Out_Menu_Items_Init (void);
void Out_Menu_Items (void);
//==================
//==================
bool proc_menu_keys (void);
//==================
#endif
//==================
#include "menu.h"
//==================
//================
menu_item __flash *CurrMenuItem; // Текущий пункт меню.
menu_item __flash *BeginCurrMenuLevel; // Начало массива текущего уровня меню.
menu_item __flash *temp_menu;
menu_item __flash Null_Menu = {(void*)0, (void*)0, (void*)0, (void*)0, NULL_FUNC, NULL_FUNC, NULL_FUNC, NULL_FUNC, {NULL_TEXT}};
void (*MenuFuncPtr)(void);
//================
//======================
// Уровни, пункты, текст - все выводится автоматом.
// Так как все переходы по меню расписаны в структуре, то отпадает надобность в запоминании перемещений по меню.
//======================
//==================
bool Set_Menu_Level (menu_item __flash *NewMenu)
{
if ((void*)NewMenu == (void*)&NULL_ENTRY)
return false;
else
{
CurrMenuItem = NewMenu;
clr_dsp_buf ();
Print_Buf (1, CurrMenuItem->Text); // вывод названия пункта меню.
GO_MENU_FUNC (MENU_INIT_FUNC);
return true;
}
}
//==================
//==================
bool Set_Menu_Item (menu_item __flash *NewMenu)
{
if ((void*)NewMenu == (void*)&NULL_ENTRY)
return false;
else
{
CurrMenuItem = NewMenu;
clr_dsp_buf ();
Print_Buf (1, CurrMenuItem->Text); // вывод названия пункта меню.
GO_MENU_FUNC (MENU_INIT_FUNC);
return true;
}
}
//==================
//==================
bool MenuFunc (FuncPtr* Function)
{
if ((void*) Function == (void*) NULL_FUNC)
return false;
else
{
((FuncPtr) Function)();
return true;
}
}
//==================
//==================
//---------- Навигация по меню. ----------
// Кнопки:
// Esc. Выход из меню. Переход на родительский уровень. Отмена.
// Enter. Вход в меню. Переход на пункт меню. Вход в режим редактирования параметра. Сохранение параметра.
// Plus. Следующий пункт меню. Изменение параметра. Увеличить значение параметра.
// Minus. Предыдущий пункт меню. Изменение параметра. Уменьшить значение параметра.
//----------
// Esc. Parent Level.
// Enter. Child Level. Func.
// Plus. Next Item. Func.
// Minus. Prev Item. Func.
//----------
bool proc_menu_keys (void)
{
if (Get_Event (EV_ID_KEY_PRESSED))
{
switch (Get_Key_Code ())
{
case KEY_ESC_COD:
if (SET_MENU_LEVEL (PARENT))
return true;
else
return false;
case KEY_ENTER_COD:
if (CurrMenuItem -> EnterFunc != NULL_FUNC)
GO_MENU_FUNC (ENTER_FUNC);
if (SET_MENU_LEVEL (CHILD))
return true;
else
return false;
case KEY_PLUS_COD:
if (CurrMenuItem -> PlusFunc != NULL_FUNC)
{
GO_MENU_FUNC (PLUS_FUNC);
return false;
}
if (SET_MENU_LEVEL (NEXT))
return true;
else
return false;
case KEY_MINUS_COD:
if (CurrMenuItem -> MinusFunc != NULL_FUNC)
{
GO_MENU_FUNC (MINUS_FUNC);
return false;
}
if (SET_MENU_LEVEL (PREV))
return true;
else
return false;
default:
return false;
}
}
else
return false;
}
//==================
Вт май 05, 2020 15:19:10
именно это я и реализовал, помимо всего прочего, что вы могли бы заметить самии по примеру кода, что я приводил в первом сообщении, если бы не были так самоуверены.Demiurg писал(а):Если в этом топике кто-нибудь поможет выработать решение с полем параметры, топик можно будет считать успешным.
Задача, написать макрос, который позволит сделать поле Parameters не обязательным. Как пример.
Вт май 05, 2020 15:52:41
Вт май 05, 2020 16:06:59
универсальность есть. например, стандартная библиотека Си - разве она не универсальна? универсальность достигается предоставлением основных решений наиболее характерных задач. а остальное - да, требует усилий.Demiurg писал(а):универсальности нет
Вт май 05, 2020 16:34:09
Вт май 05, 2020 16:43:25
я вам писал, что вы слишком самоуверены.Demiurg писал(а):Я вам писал, что вы не поняли сути MicroMenu
не знаю, но представить могуDemiurg писал(а):Знаете, как это дико выбешивает, если нужно настроить аппарат, а у него меню на сотни пунктов.
так вы сформулируйте эти проблемы, потому как я не понимаю, о чем вы говорите, после того, как я расписал и продемонстрировал на видео уже реализованные возможности. что еще не решенным осталось-то?Demiurg писал(а):если ваш проект решит многие известные проблемы с меню
я за славой не гонюсьDemiurg писал(а):он будет иметь неплохой успех
Вт май 05, 2020 18:27:24
constexpr MenuItem menuItems[] =
{
{ 0, "BEEP", beep },
{ 0, "TEST", nullptr, PROP_U8(u8, NOSTORE, 0, 12) },
{ 0, "MOTOR", motor, PROP_BOOL(motor_state, NOSTORE, sf("STOP"), sf("RUN")) },
{ 0, "SUBMENU" },
{ 1, "STOP DEMO 1", done);
{ 1, "STOP DEMO 2", done);
{ 1, "STOP SUB");
{ 2, "SUB STOP DEMO 1", done },
{ 2, "SUB STOP DEMO 2", done },
{ 2, "SUB STOP DEMO 3", done },
{ 0, "TEMPERATURE", nullptr, PROP_I16(vfr, NOSTORE, -20, 20) },
{ 0, "LOAD", load },
{ 0, "SAVE & EXIT", save }
};
Вт май 05, 2020 20:05:53
// NAME PARENT CHILD NEXT PREV TEXT // Можно так.
// NAME TEXT PARENT CHILD NEXT PREV // Можно так. Кому как нравится.
//===========
// NAME PARENT CHILD NEXT PREV TEXT
//----------
//----------
MAKE_MENU (L_DEFAULT, NULL_ENTRY, L_L1_I1, NULL_ENTRY, NULL_ENTRY, "ПАРАМЕТРЫ");
MAKE_MENU (L_L1_I1, L_DEFAULT, NULL_ENTRY, L_L1_I2, NULL_ENTRY, "Пункт 1");
Вт май 05, 2020 21:48:02
не те два байта, а разное количество байт, в зависимости от того, какие именно поля в структуре присутствуют, а какие отсутствуют. вся структура меню размещается во flash.Demiurg писал(а):Есть подозрение, что это и есть те два байта о которых я писал чуток выше. То есть спрятано в программе, но не во Flash
Ср май 06, 2020 13:48:12
Ср май 06, 2020 14:08:07
Ср май 06, 2020 14:28:43
Ср май 06, 2020 15:11:19
проблема лично для меня в том, что я пока не смог написать макрос, который бы позволял создавать массив указателей на структуры переменной длины прямо в инициализации самого массива. для списка взял идею из MicroMenu, а вот для массива не выходит - ругается компилятор на неопределенный размер структуры... или я чего-то не понимаю, или это невозможно в принципе.WiseLord писал(а):Ведь технически, эти поля - лишние.
я сделал на трех. проблему с возвратом из субменю к первому пункту решил - она решаема для любого количества пунктов любых реализаций, и в примерах проектов, которые я выложил вместе с исходниками, это демонстрируется: возврат из субменю происходит к выделению "входного" пункта.Demiurg писал(а):нужно 4 поля. Parent, Child, Next, Prev.
анонимный union: для пункта "команда" не нужно поле "субменю", но нужно поле "функция", для пункта "субменю" не нужно поле "функция", но нужно поле "субменю" - если сделать оба поля в union-е, то вместо двух полей будет фактически одно... так можно и для трех, и для четырех сделать - было бы желание.Demiurg писал(а):как ты реализовал необязательный параметр.
Ср май 06, 2020 17:40:28