/* ---------------- menubar.c -------------- */ #include "dflat.h" static void reset_menubar(WINDOW); static struct { int x1, x2; /* position in menu bar */ char sc; /* shortcut key value */ } menu[10]; static int mctr; MBAR *ActiveMenuBar; static MENU *ActiveMenu; static WINDOW mwnd; static int Selecting; static WINDOW Cascaders[MAXCASCADES]; static int casc; static WINDOW GetDocFocus(WINDOW); static void SetFocusMsg(WINDOW wnd, PARAM p1) { if ((int) p1) { if (ActiveMenuBar->ActiveSelection == -1) ActiveMenuBar->ActiveSelection = 0; if (inFocus == wnd) SendMessage(wnd, PAINT, 0, 0); } else { SendMessage(wnd, PAINT, 0, 0); SendMessage(GetParent(wnd), ADDSTATUS, 0, 0); } } static void CommandMsg(WINDOW wnd, PARAM p1, PARAM p2) { if (isCascadedCommand(ActiveMenuBar, (int)p1)) { /* find the cascaded menu based on command id in p1 */ MENU *mnu = ActiveMenu+mctr; while (mnu->Title != (void *)-1) { if (mnu->CascadeId == (int) p1) { if (casc < MAXCASCADES) { Cascaders[casc++] = mwnd; SendMessage(wnd, SELECTION, (PARAM)(mnu-ActiveMenu), TRUE); } break; } mnu++; } } else { if (mwnd != NULL) SendMessage(mwnd, CLOSE_WINDOW, 0, 0); SendMessage(GetDocFocus(wnd), SETFOCUS, TRUE, 0); PostMessage(GetParent(wnd), COMMAND, p1, p2); } } static void BuildMenuMsg(WINDOW wnd, PARAM p1) { int offset = 3; reset_menubar(wnd); mctr = 0; ActiveMenuBar = (MBAR *) p1; ActiveMenu = ActiveMenuBar->PullDown; while (ActiveMenu->Title != NULL && ActiveMenu->Title != (void*)-1) { char *cp; if (strlen(GetText(wnd)+offset) < strlen(ActiveMenu->Title)+3) break; GetText(wnd) = realloc(GetText(wnd), strlen(GetText(wnd))+5); memmove(GetText(wnd) + offset+4, GetText(wnd) + offset, strlen(GetText(wnd))-offset+1); CopyCommand(GetText(wnd)+offset, ActiveMenu->Title, FALSE, wnd->WindowColors [STD_COLOR] [BG]); menu[mctr].x1 = offset; offset += strlen(ActiveMenu->Title) + (3+MSPACE); menu[mctr].x2 = offset-MSPACE; cp = strchr(ActiveMenu->Title, SHORTCUTCHAR); if (cp) menu[mctr].sc = tolower(*(cp+1)); mctr++; ActiveMenu++; } ActiveMenu = ActiveMenuBar->PullDown; } static void PaintMsg(WINDOW wnd) { if (wnd == inFocus) SendMessage(GetParent(wnd), ADDSTATUS, 0, 0); SetStandardColor(wnd); wputs(wnd, GetText(wnd), 0, 0); if (ActiveMenuBar->ActiveSelection != -1 && (wnd == inFocus || mwnd != NULL)) { char *sel; char *cp; if ((sel = malloc(200)) != NULL) { int offset = menu[ActiveMenuBar->ActiveSelection].x1; int offset1 = menu[ActiveMenuBar->ActiveSelection].x2; GetText(wnd)[offset1] = '\0'; SetReverseColor(wnd); memset(sel, '\0', 200); strcpy(sel, GetText(wnd)+offset); cp = strchr(sel, CHANGECOLOR); if (cp != NULL) *(cp + 2) = background | 0x80; wputs(wnd, sel, offset-ActiveMenuBar->ActiveSelection*4, 0); GetText(wnd)[offset1] = ' '; if (!Selecting && mwnd == NULL && wnd == inFocus) { char *st = ActiveMenu[ActiveMenuBar->ActiveSelection].StatusText; if (st != NULL) SendMessage(GetParent(wnd), ADDSTATUS, (PARAM)st, 0); } free(sel); } } } static void KeyboardMsg(WINDOW wnd, PARAM p1) { MENU *mnu; if (mwnd == NULL) { /* ----- search for menu bar shortcut keys ---- */ int c = tolower((int)p1); int a = AltConvert((int)p1); int j; for (j = 0; j < mctr; j++) { if ((inFocus == wnd && menu[j].sc == c) || (a && menu[j].sc == a)) { SendMessage(wnd, SELECTION, j, 0); return; } } } /* -------- search for accelerator keys -------- */ mnu = ActiveMenu; while (mnu->Title != (void *)-1) { struct PopDown *pd = mnu->Selections; if (mnu->PrepMenu) (*(mnu->PrepMenu))(GetDocFocus(wnd), mnu); while (pd->SelectionTitle != NULL) { if (pd->Accelerator == (int) p1) { if (pd->Attrib & INACTIVE) beep(); else { if (pd->Attrib & TOGGLE) pd->Attrib ^= CHECKED; SendMessage(GetDocFocus(wnd), SETFOCUS, TRUE, 0); PostMessage(GetParent(wnd), COMMAND, pd->ActionId, 0); } return; } pd++; } mnu++; } switch ((int)p1) { case F1: if (ActiveMenu != NULL && (mwnd == NULL || (ActiveMenu+ActiveMenuBar->ActiveSelection)-> Selections[0].SelectionTitle == NULL)) { DisplayHelp(wnd, (ActiveMenu+ActiveMenuBar->ActiveSelection)->Title+1); return; } break; case '\r': if (mwnd == NULL && ActiveMenuBar->ActiveSelection != -1) SendMessage(wnd, SELECTION, ActiveMenuBar->ActiveSelection, 0); break; case F10: if (wnd != inFocus && mwnd == NULL) { SendMessage(wnd, SETFOCUS, TRUE, 0); break; } /* ------- fall through ------- */ case ESC: if (inFocus == wnd && mwnd == NULL) { ActiveMenuBar->ActiveSelection = -1; SendMessage(GetDocFocus(wnd), SETFOCUS, TRUE, 0); SendMessage(wnd, PAINT, 0, 0); } break; case FWD: ActiveMenuBar->ActiveSelection++; if (ActiveMenuBar->ActiveSelection == mctr) ActiveMenuBar->ActiveSelection = 0; if (mwnd != NULL) SendMessage(wnd, SELECTION, ActiveMenuBar->ActiveSelection, 0); else SendMessage(wnd, PAINT, 0, 0); break; case BS: if (ActiveMenuBar->ActiveSelection == 0) ActiveMenuBar->ActiveSelection = mctr; --ActiveMenuBar->ActiveSelection; if (mwnd != NULL) SendMessage(wnd, SELECTION, ActiveMenuBar->ActiveSelection, 0); else SendMessage(wnd, PAINT, 0, 0); break; default: break; } } static void LeftButtonMsg(WINDOW wnd, PARAM p1) { int i = BarSelection((int) p1 - GetLeft(wnd)); if (i < mctr) if (i != ActiveMenuBar->ActiveSelection || mwnd == NULL) SendMessage(wnd, SELECTION, i, 0); } static void SelectionMsg(WINDOW wnd, PARAM p1, PARAM p2) { int offset = 3, wd, mx, my; MENU *mnu; Selecting = TRUE; mnu = ActiveMenu+(int)p1; if (mnu->PrepMenu != NULL) (*(mnu->PrepMenu))(GetDocFocus(wnd), mnu); wd = MenuWidth(mnu->Selections); if (p2) { mx = GetLeft(inFocus) + WindowWidth(inFocus) - 1; my = GetTop(inFocus) + inFocus->selection; } else { if (mwnd != NULL) { SendMessage(wnd, SETFOCUS, TRUE, 0); SendMessage(mwnd, CLOSE_WINDOW, 0, 0); } ActiveMenuBar->ActiveSelection = (int) p1; offset = menu[ActiveMenuBar->ActiveSelection].x1 - 4 * ActiveMenuBar->ActiveSelection; if (offset > WindowWidth(wnd)-wd) offset = WindowWidth(wnd)-wd; mx = GetLeft(wnd)+offset; my = GetTop(wnd)+1; } mwnd = CreateWindow(POPDOWNMENU, NULL, mx, my, MenuHeight(mnu->Selections), wd, NULL, wnd, NULL, 0); AddAttribute(mwnd, SHADOW); if (mnu->Selections[0].SelectionTitle != NULL) { SendMessage(mwnd, BUILD_SELECTIONS, (PARAM) mnu, 0); SendMessage(mwnd, SETFOCUS, TRUE, 0); } else SendMessage(wnd, PAINT, 0, 0); Selecting = FALSE; } static void ClosePopdownMsg(WINDOW wnd, PARAM p1) { if (casc > 0) SendMessage(Cascaders[--casc], CLOSE_WINDOW, p1, 0); else { mwnd = NULL; ActiveMenuBar->ActiveSelection = -1; if (!Selecting) SendMessage(GetDocFocus(wnd), SETFOCUS, TRUE, 0); SendMessage(wnd, PAINT, 0, 0); } } static void CloseWindowMsg(WINDOW wnd) { if (GetText(wnd) != NULL) { free(GetText(wnd)); GetText(wnd) = NULL; } mctr = 0; ActiveMenuBar->ActiveSelection = -1; ActiveMenu = NULL; ActiveMenuBar = NULL; } int MenuBarProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2) { int rtn; switch (msg) { case CREATE_WINDOW: reset_menubar(wnd); break; case SETFOCUS: rtn = BaseWndProc(MENUBAR, wnd, msg, p1, p2); SetFocusMsg(wnd, p1); return rtn; case COMMAND: CommandMsg(wnd, p1, p2); return TRUE; case BUILDMENU: BuildMenuMsg(wnd, p1); break; case PAINT: if (!isVisible(wnd) || GetText(wnd) == NULL) break; PaintMsg(wnd); return FALSE; case KEYBOARD: KeyboardMsg(wnd, p1); return TRUE; case LEFT_BUTTON: LeftButtonMsg(wnd, p1); return TRUE; case SELECTION: SelectionMsg(wnd, p1, p2); break; case BORDER: return TRUE; case INSIDE_WINDOW: return InsideRect(p1, p2, WindowRect(wnd)); case CLOSE_POPDOWN: ClosePopdownMsg(wnd, p1); return TRUE; case CLOSE_WINDOW: rtn = BaseWndProc(MENUBAR, wnd, msg, p1, p2); CloseWindowMsg(wnd); return rtn; default: break; } return BaseWndProc(MENUBAR, wnd, msg, p1, p2); } static WINDOW GetDocFocus(WINDOW wnd) { WINDOW DocFocus = Focus.LastWindow; CLASS cl; while ((cl = GetClass(DocFocus)) == MENUBAR || cl == POPDOWNMENU || cl == STATUSBAR || cl == APPLICATION) { if ((DocFocus = PrevWindow(DocFocus)) == NULL) { DocFocus = GetParent(wnd); break; } } return DocFocus; } static void reset_menubar(WINDOW wnd) { if ((GetText(wnd) = realloc(GetText(wnd), SCREENWIDTH+5)) != NULL) { memset(GetText(wnd), ' ', SCREENWIDTH); *(GetText(wnd)+WindowWidth(wnd)) = '\0'; } } int BarSelection(int mx) { int i; for (i = 0; i < mctr; i++) if (mx >= menu[i].x1-4*i && mx <= menu[i].x2-4*i-5) break; return i; }