/* mswmenus - Low Level Menu Objects for Microsoft Windows */
/* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney */
/* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz */
/* You may give out copies of this software; for conditions see the */
/* file COPYING included with this distribution. */
/***********************************************************************/
/** **/
/** General Includes and Definitions **/
/** **/
/***********************************************************************/
#include "xlisp.h"
#include "xlstat.h"
/* external variables */
extern LVAL s_title, s_items, s_enabled, s_id, s_menu_list,
s_mark, s_menu, s_menu_proto, s_menu_item_proto, sk_select,
sk_update, sk_do_action, s_hardware_address;
extern HWND hWndFrame, hWndClient;
extern HMENU hMainMenu, hWinMenu;
/* static variables */
static int InPopup = FALSE, PopupItem = 0;
#define get_menu_id(m) ((int) getfixnum(slot_value(m, s_id)))
#define FIRSTMENU 32
#define MAXITEMS 128
#define LASTMENU 256
#define MENUITEMMENU(x) ((x)/MAXITEMS)
#define MENUITEMITEM(x) ((x)%MAXITEMS)
#define MAKEITEMINDEX(m,i) (((m)*MAXITEMS)+(i))
/* forward declaration */
static char *get_item_string(LVAL item);
/***********************************************************************/
/** **/
/** Support Functions **/
/** **/
/***********************************************************************/
static LVAL GetMenuList(void)
{
return(slot_value(getvalue(s_menu_proto), s_menu_list));
}
/* find the position of the item in the menu */
static int get_item_position(LVAL menu, LVAL item)
{
int i;
LVAL items;
for (items = slot_value(menu, s_items), i = 0;
consp(items) && car(items) != item; i++, items = cdr(items))
;
if (item != car(items)) xlfail("item not in the menu");
return(i);
}
/* find index in menu bar; returns -1 if not installed */
static int get_menu_position(HMENU addr)
{
int n, i;
if (addr == NULL) return -1;
n = GetMenuItemCount(hMainMenu);
for (i = 0; i < n; i++)
if (addr == GetSubMenu(hMainMenu, i))
return(i);
return(-1);
}
void MSWResetMenus(void)
{
InPopup = FALSE;
PopupItem = 0;
}
/* ### this should be in the hardware objects file ### */
static void zero_hardware_address(LVAL menu)
{
LVAL addr = slot_value(menu, s_hardware_address);
if (consp(addr) && consp(cdr(addr)))
car(cdr(addr)) = cvfixnum((FIXTYPE) 0);
}
/***********************************************************************/
/** **/
/** Event Loop Interface **/
/** **/
/***********************************************************************/
BOOL IsLispMenuItem(WORD wParam)
{
LVAL next;
int m;
m = MENUITEMMENU(wParam);
for (next = GetMenuList(); consp(next); next = cdr(next))
if (StMObAllocated(car(next)) && m == get_menu_id(car(next)))
return(TRUE);
return(FALSE);
}
BOOL IsLispMenuHandle(HMENU wParam)
{
LVAL next;
for (next = GetMenuList(); consp(next); next = cdr(next))
if (StMObAllocated(car(next)) && wParam == get_menu_address(car(next)))
return(TRUE);
return(FALSE);
}
void LispMenuSelect(WORD wParam)
{
LVAL next;
int m, i;
m = MENUITEMMENU(wParam);
i = MENUITEMITEM(wParam);
for (next = GetMenuList(); consp(next); next = cdr(next)) {
if (StMObAllocated(car(next)) && m == get_menu_id(car(next))) {
if (InPopup) PopupItem = i + 1;
else send_callback_message1(car(next), sk_select, i + 1);
return;
}
}
}
void LispMenuUpdate(HMENU wParam)
{
if (! InPopup) send_callback_message(get_menu_by_hardware(wParam), sk_update);
}
/***********************************************************************/
/** **/
/** Menu Functions **/
/** **/
/***********************************************************************/
int StMObInstalled(LVAL m)
{
return(StMObAllocated(m) && get_menu_position(get_menu_address(m)) != -1);
}
/* find menu object with given hardware address */
LVAL get_menu_by_hardware(HMENU m)
{
LVAL menu = NIL, next;
for (next = GetMenuList();
menu == NIL && consp(next); next = cdr(next))
if (StMObAllocated(car(next)) && m == get_menu_address(car(next)))
menu = car(next);
if (menu == NIL) xlfail("can't find menu with this handle");
return(menu);
}
/* allocate an internal menu */
static int id_in_use(int id)
{
LVAL next;
for (next = GetMenuList(); consp(next); next = cdr(next)) {
if (id == get_menu_id(car(next))) return(TRUE);
}
return(FALSE);
}
static int unique_id(void)
{
int id;
for (id = FIRSTMENU; id < LASTMENU; id++) {
if (! id_in_use(id)) return(id);
}
xlfail("too many menus");
return(0);
}
void StMObAllocateMach(LVAL menu)
{
HMENU theMenu;
int menuID;
menuID = unique_id();
theMenu = CreatePopupMenu();
if (! theMenu) xlfail("menu allocation failed");
set_menu_address(theMenu, menu);
set_slot_value(menu, s_id, cvfixnum((FIXTYPE) menuID));
}
/* dispose of a macintosh menu */
void StMObDisposeMach(LVAL menu)
{
HWND addr;
if (StMObInstalled(menu)) StMObRemove(menu);
if (StMObAllocated(menu)) {
/* test is needed because menu is destroyed after deleting from menu bar */
addr = get_menu_address(menu);
if (addr) DestroyMenu((HMENU) addr);
}
}
/* add items to a macintosh internal menu */
void StMObAppendItems(LVAL menu, LVAL items)
{
LVAL item;
char *s;
int i, flags, id;
HMENU theMenu;
if (StMObAllocated(menu)) {
theMenu = get_menu_address(menu);
id = get_menu_id(menu);
i = llength(slot_value(menu, s_items)) - llength(items);
if (i < 0) xlfail("append list should not exceed item list");
for (; consp(items); items = cdr(items), i++) {
item = car(items);
s = get_item_string(item);
if (s[0] == '-') AppendMenu((HMENU) theMenu, MF_SEPARATOR, 0, NULL);
else {
flags = MF_STRING;
if (slot_value(item, s_mark) != NIL) flags |= MF_CHECKED;
if (slot_value(item, s_enabled) == NIL) flags |= MF_GRAYED;
AppendMenu((HMENU) theMenu, flags, MAKEITEMINDEX(id, i), s);
}
}
}
}
/* remove item from a menu */
/* this thing is so involved because the item id's have to be fixed up */
/* to reflect the shift in position */
void StMObDeleteItem(LVAL menu, LVAL item)
{
HMENU addr;
int n, i, j, id, flags;
LVAL items;
char *s;
if (StMObAllocated(menu)) {
addr = get_menu_address(menu);
id = get_menu_id(menu);
i = get_item_position(menu, item);
for (j = 0, items = slot_value(menu, s_items);
j < i && consp(items);
j++, items = cdr(items));
n = GetMenuItemCount((HMENU) addr);
for (; i < n; n--) DeleteMenu((HMENU) addr, i, MF_BYPOSITION);
if (consp(items)) items = cdr(items);
for (; consp(items); items = cdr(items), i++) {
item = car(items);
s = get_item_string(item);
if (s[0] == '-') AppendMenu((HMENU) addr, MF_SEPARATOR, 0, NULL);
else {
flags = MF_STRING;
if (slot_value(item, s_mark) != NIL) flags |= MF_CHECKED;
if (slot_value(item, s_enabled) == NIL) flags |= MF_GRAYED;
AppendMenu((HMENU) addr, flags, MAKEITEMINDEX(id, i), s);
}
}
}
}
/* install a menu */
void StMObInstall(LVAL menu)
{
int pos, enabled;
LVAL title;
title = slot_value(menu, s_title);
if (! stringp(title)) xlfail("title must be a string");
pos = get_menu_position(hWinMenu);
if (pos != -1 && ! StMObInstalled(menu)) {
if (! StMObAllocated(menu)) StMObAllocate(menu);
InsertMenu(hMainMenu,
pos,
MF_POPUP|MF_BYPOSITION,
(UINT) get_menu_address(menu),
(char *) getstring(title));
enabled = (slot_value(menu, s_enabled) != NIL) ? TRUE : FALSE;
EnableMenuItem(hMainMenu,
pos,
(enabled ? MF_ENABLED : MF_GRAYED) | MF_BYPOSITION);
SendMessage(hWndClient, WM_MDISETMENU, (WPARAM)hMainMenu,(LPARAM)hWinMenu);
DrawMenuBar(hWndFrame);
}
}
/* remove a menu */
void StMObRemove(LVAL menu)
{
int m;
if (! StMObAllocated(menu)) return;
m = get_menu_position(get_menu_address(menu));
if (m != -1) {
DeleteMenu(hMainMenu, m, MF_BYPOSITION);
SendMessage(hWndClient, WM_MDISETMENU, (WPARAM)hMainMenu,(LPARAM)hWinMenu);
DrawMenuBar(hWndFrame);
/*
* DeleteMenu disposes of the popup menu, so this is added to avoid
* disposing of an invalid handle -- hopefully it does not cause
* other problems.
*/
zero_hardware_address(menu);
}
if (StMObAllocated(menu)) StMObDispose(menu);
}
/* enable or disable a menu */
void StMObEnable(LVAL menu, int enable)
{
int m;
HMENU addr;
if (StMObAllocated(menu) && StMObInstalled(menu)) {
addr = get_menu_address(menu);
m = get_menu_position(addr);
EnableMenuItem(hMainMenu,
m,
(enable ? MF_ENABLED : MF_GRAYED) | MF_BYPOSITION);
DrawMenuBar(hWndFrame);
}
set_slot_value(menu, s_enabled, (enable) ? s_true : NIL);
}
int StMObPopup(LVAL menu, int left, int top, LVAL window)
{
HMENU theMenu;
HWND w;
POINT pt;
if (window == NIL || (w = GETWINDOWADDRESS(window)) == 0)
w = hWndFrame;
pt.x = left; pt.y = top;
ClientToScreen((HWND) w, &pt);
left = pt.x; top = pt.y;
InPopup = TRUE;
PopupItem = 0;
StMObAllocate(menu);
theMenu = get_menu_address(menu);
if (TrackPopupMenu((HMENU) theMenu, 0, left, top, 0, (HWND) w, NULL)) {
MSG msg;
extern HWND hWndClient;
extern HACCEL hAccel;
if (PeekMessage(&msg, w, WM_COMMAND, WM_COMMAND, PM_REMOVE) &&
! TranslateMDISysAccel(hWndClient, &msg) &&
! TranslateAccelerator(hWndFrame, hAccel, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
StMObDispose(menu);
InPopup = FALSE;
return(PopupItem);
}
/***********************************************************************/
/** **/
/** Menu Item Functions **/
/** **/
/***********************************************************************/
/* Get a string for use by AppendMenu. */
static char *get_item_string(LVAL item)
{
LVAL title;
if (! menu_item_p(item)) xlerror("not a menu item", item);
title = slot_value(item, s_title);
if (! stringp(title)) xlerror("title is not a string", title);
return((char *) getstring(title));
}
/* adjust internal implementation of allocated menu to new instance value */
void StMObSetItemProp(LVAL item, int which)
{
char *s;
HMENU theMenu;
LVAL menu, title;
int i, flags, id;
menu = slot_value(item, s_menu);
if (menu != NIL && StMObAllocated(menu)) {
theMenu = get_menu_address(menu);
id = get_menu_id(menu);
i = get_item_position(menu, item);
title = slot_value(item, s_title);
if (! stringp(title))
xlerror("title is not a string", title);
s = (char *) getstring(title);
if (s[0] == '-' && which != 'T') return;
switch (which) {
case 'T':
if (s[0] == '-') {
flags = MF_SEPARATOR | MF_BYPOSITION;
ModifyMenu((HMENU) theMenu, i, flags, 0, NULL);
}
else {
flags = MF_STRING | MF_BYPOSITION;
flags |= (slot_value(item, s_mark) != NIL) ? MF_CHECKED : MF_UNCHECKED;
flags |= (slot_value(item, s_enabled) != NIL) ? MF_ENABLED : MF_GRAYED;
ModifyMenu((HMENU) theMenu, i, flags, MAKEITEMINDEX(id, i), s);
}
break;
case 'K': break;
case 'M':
flags = (slot_value(item, s_mark) != NIL) ? MF_CHECKED : MF_UNCHECKED;
flags |= MF_BYPOSITION;
CheckMenuItem((HMENU) theMenu, i, flags);
break;
case 'A': break;
case 'E':
flags = (slot_value(item, s_enabled) != NIL) ? MF_ENABLED : MF_GRAYED;
flags |= MF_BYPOSITION;
EnableMenuItem((HMENU) theMenu, i, flags);
break;
default: xlfail("unknown item instance variable");
}
}
}
syntax highlighted by Code2HTML, v. 0.9.1