#help_index "Menus" #help_file "::/Doc/Menus" CTask *MenuTask() { CTask *res = sys_focus_task; while (res && !res->cur_menu) res = res->parent_task; return res; } CMenuEntry *sys_cur_submenu_entry = NULL; public CMenuEntry *MenuSubEntryFind(CMenuEntry *haystack_first, U8 *needle_entry_name) {//You probably don't need this. Use dir / and MenuEntryFind(). while (haystack_first) { if (!StrCompare(haystack_first->name, needle_entry_name)) return haystack_first; haystack_first = haystack_first->next; } return NULL; } public CMenuEntry *MenuEntryFind(CMenu *haystack_menu, U8 *needle_full_name) {//Find pulldown entry. Fs->cur_menu is probably the menu you want. //Just 2 levels -- across top and down are valid, currently. U8 *st, *st2; CMenuEntry *tmpse; if (!haystack_menu || !needle_full_name) return NULL; st = StrNew(needle_full_name); st2 = StrNew(needle_full_name); tmpse = (&haystack_menu->sub)(U8 *) - offset(CMenuEntry.sub); while (*st && tmpse) { StrFirstRemove(st, "/", st2); tmpse=MenuSubEntryFind(tmpse->sub, st2); } Free(st); Free(st2); return tmpse; } CMenuEntry *MenuNewSub(CCompCtrl *cc, CTask *task) { CMenuEntry *tmpme = NULL, *tmpse; if (cc->token==TK_IDENT) { tmpme = CAlloc(sizeof(CMenuEntry),task); if (StrLen(cc->cur_str) > 31) cc->cur_str[31] = 0; StrCopy(tmpme->name, cc->cur_str); if (Lex(cc) == '(') { tmpme->message_code = MESSAGE_KEY_DOWN_UP; if (Lex(cc) != ',' && cc->token != ')') tmpme->message_code = LexExpressionI64(cc); if (cc->token == ',') Lex(cc); if (cc->token != ',' && cc->token != ')') tmpme->arg1 = LexExpressionI64(cc); if (cc->token == ',') Lex(cc); if (cc->token != ',' && cc->token != ')') tmpme->arg2 = LexExpressionI64(cc); if (cc->token != ')') LexExcept(cc, "Missing ')' at "); if (Lex(cc) != ';') LexExcept(cc, "Missing ';' at"); Lex(cc); //Skip ; } else if (cc->token == '{') { Lex(cc); //Skip { tmpme->dir = TRUE; tmpse = &tmpme->sub; while (tmpse && cc->token != '}') tmpse = tmpse->next = MenuNewSub(cc, task); if (cc->token != '}') LexExcept(cc, "Missing '}' at "); else Lex(cc); //Skip } } else LexExcept(cc, "Expecting '{' at "); } return tmpme; } public CMenu *MenuNew(U8 *st, I64 flags = 0, CTask *task = NULL) {//Parse a menu. You probably don't need this. CMenu *m; CMenuEntry *tmpse; CCompCtrl *cc = CompCtrlNew(st, CCF_DONT_FREE_BUF); if (!task) task = Fs; Lex(cc); m = CAlloc(sizeof(CMenu), task); m->task = task; m->flags = flags; m->attr = BLUE << 4 + YELLOW; tmpse = &m->sub; while (tmpse) tmpse = tmpse->next = MenuNewSub(cc, task); CompCtrlDel(cc); return m; } public CMenu *MenuFile(U8 *filename, I64 flags = 0, CTask *task = NULL) {//Parse a pulldown menu file. You probably don't need this. CMenu *m; U8 *st = MStrPrint("#include \"%s\"", filename); m = MenuNew(st, flags, task); Free(st); return m; } U0 MenuDelSub(CMenuEntry *tmpme) { CMenuEntry *tmpse, *tmpse1; if (tmpme) { tmpse = tmpme->sub; while (tmpse) { tmpse1 = tmpse->next; MenuDelSub(tmpse); tmpse = tmpse1; } Free(tmpme); } } public U0 MenuDel(CMenu *m) {//Delete a manu. You probably don't need this. CMenuEntry *tmpme, *tmpme1; if (!m) return; tmpme = m->sub; while (tmpme) { tmpme1 = tmpme->next; MenuDelSub(tmpme); tmpme = tmpme1; } Free(m); } I64 MenuEntryWidth(CMenuEntry *tmpme) { I64 res = StrLen(tmpme->name); CMenuEntry *tmpse = tmpme->sub; while (tmpse) { res = MaxI64(res, StrLen(tmpse->name)); tmpse = tmpse->next; } return res + 1; } public CMenu *MenuPush(U8 *st) {//Save old pulldown menu and replace with new from str. CMenu *m = MenuNew(st); m->next = Fs->cur_menu; Fs->cur_menu = m; return m; } public CMenu *MenuFilePush(U8 *filename) {//Save old pulldown menu and replace with new from file. CMenu *m = MenuFile(filename); m->next = Fs->cur_menu; Fs->cur_menu = m; return m; } public U0 MenuPop() {//Restore old pulldown menu. Delete just-deactivated menu. CMenu *m = Fs->cur_menu; if (!m) return; Fs->cur_menu = m->next; MenuDel(m); } U0 DrawMenu(CDC *dc) { CMenu *m; CMenuEntry *tmpme, *tmpse, *cur_submenu = NULL; U8 *st = NULL; CTask *task = MenuTask; I64 i, w, x0, y0, x1 = mouse.pos.x, y1 = mouse.pos.y; if (!TaskValidate(task) || !(m = task->cur_menu)) { sys_cur_submenu_entry = NULL; return; } dc->color = m->attr >> 4; GrRect(dc, 0, 0, GR_WIDTH, FONT_HEIGHT); x0 = 0; tmpme = m->sub; while (tmpme) { w = MenuEntryWidth(tmpme) * FONT_WIDTH; if (x0 <= x1 < x0 + w) { if (0 <= y1 < FONT_HEIGHT) { dc->color = m->attr & 15; GrRect(dc, x0, 0, w, FONT_HEIGHT); dc->color = m->attr >> 4; } else dc->color = m->attr & 15; GrPrint(dc, x0, 0, "%s", tmpme->name); y0 = FONT_HEIGHT; tmpse = tmpme->sub; while (tmpse) { if (tmpse->checked) i = m->attr ^ 0xFF; else i = m->attr; if (y0 <= y1 < y0 + FONT_HEIGHT) { if (tmpse->message_code == MESSAGE_KEY_DOWN || tmpse->message_code == MESSAGE_KEY_DOWN_UP) { if (!tmpse->arg2) tmpse->arg2 = Char2ScanCode(tmpse->arg1); st = ScanCode2KeyName(tmpse->arg2); } sys_cur_submenu_entry = cur_submenu = tmpse; dc->color = i & 15; GrRect(dc, x0, y0, w, FONT_HEIGHT); dc->color = i >> 4; GrPrint(dc, x0, y0, "%s", tmpse->name); if (st) { dc->color = i >> 4; GrRect(dc, x0 + w, y0 - FONT_HEIGHT, (StrLen(st) + 1) * FONT_WIDTH, FONT_HEIGHT * 3); dc->color = i & 15; GrPrint(dc, x0 + w, y0, "%s", st); Free(st); } } else { dc->color = i >> 4; GrRect(dc, x0, y0, w, FONT_HEIGHT); dc->color = i & 15; GrPrint(dc, x0, y0, "%s", tmpse->name); } y0 += FONT_HEIGHT; tmpse = tmpse->next; } } else { dc->color = m->attr & 15; GrPrint(dc, x0, 0, "%s", tmpme->name); } x0 += w; tmpme = tmpme->next; } sys_cur_submenu_entry = cur_submenu; }