/* ------------- popdown.c ----------- */ #include "dflat.h" static int SelectionWidth(struct DfPopDown *); static int py = -1; /* ------------ DFM_CREATE_WINDOW Message ------------- */ static int CreateWindowMsg(DFWINDOW wnd) { int rtn, adj; DfClearAttribute (wnd, DF_HASTITLEBAR | DF_VSCROLLBAR | DF_MOVEABLE | DF_SIZEABLE | DF_HSCROLLBAR); /* ------ adjust to keep popdown on screen ----- */ adj = DfGetScreenHeight()-1-wnd->rc.bt; if (adj < 0) { wnd->rc.tp += adj; wnd->rc.bt += adj; } adj = DfGetScreenWidth()-1-wnd->rc.rt; if (adj < 0) { wnd->rc.lf += adj; wnd->rc.rt += adj; } rtn = DfBaseWndProc(DF_POPDOWNMENU, wnd, DFM_CREATE_WINDOW, 0, 0); DfSendMessage(wnd, DFM_CAPTURE_MOUSE, 0, 0); DfSendMessage(wnd, DFM_CAPTURE_KEYBOARD, 0, 0); DfSendMessage(NULL, DFM_SAVE_CURSOR, 0, 0); DfSendMessage(NULL, DFM_HIDE_CURSOR, 0, 0); wnd->oldFocus = DfInFocus; DfInFocus = wnd; return rtn; } /* --------- DFM_LEFT_BUTTON Message --------- */ static void LeftButtonMsg(DFWINDOW wnd, DF_PARAM p1, DF_PARAM p2) { int my = (int) p2 - DfGetTop(wnd); if (DfInsideRect(p1, p2, DfClientRect(wnd))) { if (my != py) { DfSendMessage(wnd, DFM_LB_SELECTION, (DF_PARAM) wnd->wtop+my-1, TRUE); py = my; } } else if ((int)p2 == DfGetTop(DfGetParent(wnd))) if (DfGetClass(DfGetParent(wnd)) == DF_MENUBAR) DfPostMessage(DfGetParent(wnd), DFM_LEFT_BUTTON, p1, p2); } /* -------- BUTTON_RELEASED Message -------- */ static BOOL ButtonReleasedMsg(DFWINDOW wnd, DF_PARAM p1, DF_PARAM p2) { py = -1; if (DfInsideRect((int)p1, (int)p2, DfClientRect(wnd))) { int sel = (int)p2 - DfGetClientTop(wnd); if (*DfTextLine(wnd, sel) != DF_LINE) DfSendMessage(wnd, DFM_LB_CHOOSE, wnd->selection, 0); } else { DFWINDOW pwnd = DfGetParent(wnd); if (DfGetClass(pwnd) == DF_MENUBAR && (int)p2==DfGetTop(pwnd)) return FALSE; if ((int)p1 == DfGetLeft(pwnd)+2) return FALSE; DfSendMessage(wnd, DFM_CLOSE_WINDOW, 0, 0); return TRUE; } return FALSE; } /* --------- DFM_PAINT Message -------- */ static void PaintMsg(DFWINDOW wnd) { int wd; char sep[80], *cp = sep; char sel[80]; struct DfPopDown *ActivePopDown; struct DfPopDown *pd1; ActivePopDown = pd1 = wnd->mnu->Selections; wd = DfMenuWidth(ActivePopDown)-2; while (wd--) *cp++ = DF_LINE; *cp = '\0'; DfSendMessage(wnd, DFM_CLEARTEXT, 0, 0); wnd->selection = wnd->mnu->Selection; while (pd1->SelectionTitle != NULL) { if (*pd1->SelectionTitle == DF_LINE) DfSendMessage(wnd, DFM_ADDTEXT, (DF_PARAM) sep, 0); else { int len; memset(sel, '\0', sizeof sel); if (pd1->Attrib & DF_INACTIVE) /* ------ inactive menu selection ----- */ sprintf(sel, "%c%c%c", DF_CHANGECOLOR, wnd->WindowColors [DF_HILITE_COLOR] [DF_FG]|0x80, wnd->WindowColors [DF_STD_COLOR] [DF_BG]|0x80); strcat(sel, " "); if (pd1->Attrib & DF_CHECKED) /* ---- paint the toggle checkmark ---- */ sel[strlen(sel)-1] = DF_CHECKMARK; len=DfCopyCommand(sel+strlen(sel),pd1->SelectionTitle, pd1->Attrib & DF_INACTIVE, wnd->WindowColors [DF_STD_COLOR] [DF_BG]); if (pd1->Accelerator) { /* ---- paint accelerator key ---- */ int i; int wd1 = 2+SelectionWidth(ActivePopDown) - strlen(pd1->SelectionTitle); for (i = 0; keys[i].keylabel; i++) { if (keys[i].keycode == pd1->Accelerator) { while (wd1--) strcat(sel, " "); sprintf(sel+strlen(sel), "[%s]", keys[i].keylabel); break; } } } if (pd1->Attrib & DF_CASCADED) { /* ---- paint cascaded menu token ---- */ if (!pd1->Accelerator) { wd = DfMenuWidth(ActivePopDown)-len+1; while (wd--) strcat(sel, " "); } sel[strlen(sel)-1] = DF_CASCADEPOINTER; } else strcat(sel, " "); strcat(sel, " "); sel[strlen(sel)-1] = DF_RESETCOLOR; DfSendMessage(wnd, DFM_ADDTEXT, (DF_PARAM) sel, 0); } pd1++; } } /* ---------- DFM_BORDER Message ----------- */ static int BorderMsg(DFWINDOW wnd) { int i, rtn = TRUE; DFWINDOW currFocus; if (wnd->mnu != NULL) { currFocus = DfInFocus; DfInFocus = NULL; rtn = DfBaseWndProc(DF_POPDOWNMENU, wnd, DFM_BORDER, 0, 0); DfInFocus = currFocus; for (i = 0; i < DfClientHeight(wnd); i++) { if (*DfTextLine(wnd, i) == DF_LINE) { DfWPutch(wnd, DF_LEDGE, 0, i+1); DfWPutch(wnd, DF_REDGE, DfWindowWidth(wnd)-1, i+1); } } } return rtn; } /* -------------- DFM_LB_CHOOSE Message -------------- */ static void LBChooseMsg(DFWINDOW wnd, DF_PARAM p1) { struct DfPopDown *ActivePopDown = wnd->mnu->Selections; if (ActivePopDown != NULL) { int *attr = &(ActivePopDown+(int)p1)->Attrib; wnd->mnu->Selection = (int)p1; if (!(*attr & DF_INACTIVE)) { if (*attr & DF_TOGGLE) *attr ^= DF_CHECKED; DfPostMessage(DfGetParent(wnd), DFM_COMMAND, (ActivePopDown+(int)p1)->ActionId, p1); } else DfBeep(); } } /* ---------- DFM_KEYBOARD Message --------- */ static BOOL KeyboardMsg(DFWINDOW wnd, DF_PARAM p1, DF_PARAM p2) { struct DfPopDown *ActivePopDown = wnd->mnu->Selections; if (wnd->mnu != NULL) { if (ActivePopDown != NULL) { int c = (int)p1; int sel = 0; int a; struct DfPopDown *pd = ActivePopDown; if ((c & DF_OFFSET) == 0) c = tolower(c); a = DfAltConvert(c); while (pd->SelectionTitle != NULL) { char *cp = strchr(pd->SelectionTitle, DF_SHORTCUTCHAR); /* FIXME: DfAltConvert bug !! */ if ((cp && tolower(*(cp+1)) == c) || // (a && tolower(*(cp+1)) == a) || pd->Accelerator == c) { DfPostMessage(wnd, DFM_LB_SELECTION, sel, 0); DfPostMessage(wnd, DFM_LB_CHOOSE, sel, TRUE); return TRUE; } pd++; sel++; } } } switch ((int)p1) { case DF_F1: if (ActivePopDown == NULL) DfSendMessage(DfGetParent(wnd), DFM_KEYBOARD, p1, p2); else DfDisplayHelp(wnd, (ActivePopDown+wnd->selection)->help); return TRUE; case DF_ESC: DfSendMessage(wnd, DFM_CLOSE_WINDOW, 0, 0); return TRUE; case DF_FWD: case DF_BS: if (DfGetClass(DfGetParent(wnd)) == DF_MENUBAR) DfPostMessage(DfGetParent(wnd), DFM_KEYBOARD, p1, p2); return TRUE; case DF_UP: if (wnd->selection == 0) { if (wnd->wlines == DfClientHeight(wnd)) { DfPostMessage(wnd, DFM_LB_SELECTION, wnd->wlines-1, FALSE); return TRUE; } } break; case DF_DN: if (wnd->selection == wnd->wlines-1) { if (wnd->wlines == DfClientHeight(wnd)) { DfPostMessage(wnd, DFM_LB_SELECTION, 0, FALSE); return TRUE; } } break; case DF_HOME: case DF_END: case '\r': break; default: return TRUE; } return FALSE; } /* ----------- DFM_CLOSE_WINDOW Message ---------- */ static int CloseWindowMsg(DFWINDOW wnd) { int rtn; DFWINDOW pwnd = DfGetParent(wnd); DfSendMessage(wnd, DFM_RELEASE_MOUSE, 0, 0); DfSendMessage(wnd, DFM_RELEASE_KEYBOARD, 0, 0); DfSendMessage(NULL, DFM_RESTORE_CURSOR, 0, 0); DfInFocus = wnd->oldFocus; rtn = DfBaseWndProc(DF_POPDOWNMENU, wnd, DFM_CLOSE_WINDOW, 0, 0); DfSendMessage(pwnd, DFM_CLOSE_POPDOWN, 0, 0); return rtn; } /* - Window processing module for DF_POPDOWNMENU window class - */ int DfPopDownProc(DFWINDOW wnd, DFMESSAGE msg, DF_PARAM p1, DF_PARAM p2) { switch (msg) { case DFM_CREATE_WINDOW: return CreateWindowMsg(wnd); case DFM_LEFT_BUTTON: LeftButtonMsg(wnd, p1, p2); return FALSE; case DOUBLE_CLICK: return TRUE; case DFM_LB_SELECTION: if (*DfTextLine(wnd, (int)p1) == DF_LINE) return TRUE; wnd->mnu->Selection = (int)p1; break; case DFM_BUTTON_RELEASED: if (ButtonReleasedMsg(wnd, p1, p2)) return TRUE; break; case DFM_BUILD_SELECTIONS: wnd->mnu = (void *) p1; wnd->selection = wnd->mnu->Selection; break; case DFM_PAINT: if (wnd->mnu == NULL) return TRUE; PaintMsg(wnd); break; case DFM_BORDER: return BorderMsg(wnd); case DFM_LB_CHOOSE: LBChooseMsg(wnd, p1); return TRUE; case DFM_KEYBOARD: if (KeyboardMsg(wnd, p1, p2)) return TRUE; break; case DFM_CLOSE_WINDOW: return CloseWindowMsg(wnd); default: break; } return DfBaseWndProc(DF_POPDOWNMENU, wnd, msg, p1, p2); } /* --------- compute menu height -------- */ int DfMenuHeight(struct DfPopDown *pd) { int ht = 0; while (pd[ht].SelectionTitle != NULL) ht++; return ht+2; } /* --------- compute menu width -------- */ int DfMenuWidth(struct DfPopDown *pd) { int wd = 0, i; int len = 0; wd = SelectionWidth(pd); while (pd->SelectionTitle != NULL) { if (pd->Accelerator) { for (i = 0; keys[i].keylabel; i++) if (keys[i].keycode == pd->Accelerator) { len = max(len, (int)(2+strlen(keys[i].keylabel))); break; } } if (pd->Attrib & DF_CASCADED) len = max(len, 2); pd++; } return wd+5+len; } /* ---- compute the maximum selection width in a menu ---- */ static int SelectionWidth(struct DfPopDown *pd) { int wd = 0; while (pd->SelectionTitle != NULL) { int len = strlen(pd->SelectionTitle)-1; wd = max(wd, len); pd++; } return wd; } /* ----- copy a menu command to a display buffer ---- */ int DfCopyCommand(char *dest, char *src, int skipcolor, int bg) { char *d = dest; while (*src && *src != '\n') { if (*src == DF_SHORTCUTCHAR) { src++; if (!skipcolor) { *dest++ = DF_CHANGECOLOR; *dest++ = DfCfg.clr[DF_POPDOWNMENU] [DF_HILITE_COLOR] [DF_BG] | 0x80; *dest++ = bg | 0x80; *dest++ = *src++; *dest++ = DF_RESETCOLOR; } } else *dest++ = *src++; } return (int) (dest - d); } /* EOF */