menu.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,289 行 · 第 1/3 页
C
1,289 行
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
* DESCRIBE IT HERE!
*
****************************************************************************/
#include <ctype.h>
#include <string.h>
#include <malloc.h>
#include <assert.h>
#define INCLUDE_SHELLAPI_H
#include "winvi.h"
#include "keys.h"
#include "source.h"
/* The following value comes from Petzold - page 344 */
/* we don't want to interfere with any system id's */
#define MAX_ID 0xf000
#define FILE_LIST_ID 0xf000-11
#define LAST_FILES_ID FILE_LIST_ID-11
#define HOT_KEY_CHAR '&'
typedef struct item {
struct item *next, *prev;
UINT id;
char in_menu:1;
char is_active:1;
char is_checked:1;
char unused:5;
char *name;
char *help;
char cmd[1];
} item;
typedef struct menu {
struct menu *next, *prev;
void *item_head, *item_tail;
char has_file_list:1;
char need_hook:1;
char has_last_files:1;
char spare:5;
int num_items;
int orig_num_items;
HMENU menu_handle;
char *help;
char name[1];
} menu;
static menu mainMenu = { NULL, NULL, NULL, NULL, 0, 0, 0 };
static menu *rootMenu = &mainMenu;
static menu *currMenu = NULL;
static int selectedItem;
/* utility functions used in rest of module */
/*
* compareName - a case insensitive strcmp which ignores the embedded '&'
* characters used to indicate hot keys in menu names
*/
static int compareName( char *dst, char *src )
{
do {
while( *src == HOT_KEY_CHAR ) src++;
while( *dst == HOT_KEY_CHAR ) dst++;
if( tolower( *dst ) != tolower( *src++ ) ) {
return( FALSE );
}
} while( *dst++ );
return( TRUE );
} /* compareName */
/*
* getHotKey - get the hot key specified in a string
*/
static int getHotKey( char *str )
{
if( str == NULL ) {
return( 0 );
}
while( *str ) {
if( *str == HOT_KEY_CHAR ) {
return( toupper( *(str+1) ) - 'A' + VI_KEY( ALT_A ));
}
str++;
}
return( 0 );
} /* getHotKey */
/*
* NextMenuId - returns the next available unique idea for a menu item
*/
static UINT nextAvail;
UINT NextMenuId( void )
{
if( ++nextAvail == MAX_ID ) {
/* run through all menu item lists and 'normalize' them */
/* 0xefff menu id's should be enough so we will forget it
for now */
Message1( "YIKES! Menu id rollover! FIXME in file %s - line %d",
__FILE__, __LINE__ );
}
return( nextAvail );
} /* NextMenuId */
/*
* handleMenuCommand - this routine takes a menu and an id and executes the
* command associated with the menu item if there is an
* item with that id.
*/
static int handleMenuCommand( menu *m, UINT id )
{
item *citem;
char *str;
int len, rc;
for( citem = m->item_head; citem != NULL; citem = citem->next ) {
if( citem->id == id ) {
/* run this command */
len = strlen( citem->cmd ) + 1;
str = alloca( len );
memcpy( str, citem->cmd, len );
IMEsc();
rc = RunCommandLine( str );
#ifdef __WIN__
SetWindowCursorForReal();
#endif
return( rc );
}
}
return( MENU_COMMAND_NOT_HANDLED );
} /* handleMenuCommand */
/* special menu crap - for floaters and that guy at the corner of a window */
#define MAX_FLOAT_MENUS 4
static menu floatMenus[ MAX_FLOAT_MENUS ] = {
{ NULL, NULL, NULL, NULL, 0, 0, 0 },
{ NULL, NULL, NULL, NULL, 0, 0, 0 },
{ NULL, NULL, NULL, NULL, 0, 0, 0 },
{ NULL, NULL, NULL, NULL, 0, 0, 0 } };
static menu windowGadgetMenu =
{ NULL, NULL, NULL, NULL, 0, 0, 0 };
typedef struct special_menu {
char *name;
menu *m;
} special_menu;
static special_menu specialMenus[] = {
{ "float0", &floatMenus[ 0 ] },
{ "float1", &floatMenus[ 1 ] },
{ "float2", &floatMenus[ 2 ] },
{ "float3", &floatMenus[ 3 ] },
{ "windowgadget", &windowGadgetMenu }
};
/*
* isSpecialMenuPtr - see if a menu pointer is a special menu
*/
static bool isSpecialMenuPtr( menu *cmenu )
{
int i;
for( i=0;i<sizeof(specialMenus)/sizeof(special_menu); i++ ) {
if( cmenu == specialMenus[i].m ) {
return( TRUE );
}
}
return( FALSE );
} /* isSpecialMenuPtr */
/*
* specialMenu - check if a name is a special menu name
*/
static menu *specialMenu( char *name )
{
menu *m;
special_menu *s;
int i;
/* this is a little gross... */
m = NULL;
s = &specialMenus[ 0 ];
for( i = 0; i < sizeof(specialMenus)/sizeof(special_menu); i++, s++ ) {
if( compareName( name, s->name ) ) {
m = s->m;
break;
}
}
return( m );
} /* specialMenu */
/*
* specialMenuCommand - run a command from a specific menu
*/
static int specialMenuCommand( UINT w )
{
int i, rc;
special_menu *s;
s = &specialMenus[ 0 ];
for( i = 0; i < sizeof(specialMenus)/sizeof(special_menu); i++, s++ ) {
rc = handleMenuCommand( s->m, w );
if( rc != MENU_COMMAND_NOT_HANDLED ) {
return( rc );
}
}
return( MENU_COMMAND_NOT_HANDLED );
} /* specialMenuCommand */
/*
* Intermediate level functions used by high-level guys
*/
/*
* addMenuToMenu - adds a main level menu item
*/
static menu *addMenuToMenu( menu *m, char *name, char *help )
{
menu *new;
int name_len;
// assert( IsMenu( m->menu_handle ) );
name_len = strlen( name );
new = MemAlloc( sizeof( menu ) + name_len + strlen( help ) + 1);
new->num_items = 0;
strcpy( &new->name[0], name );
new->help = &new->name[ name_len + 1 ];
strcpy( new->help, help );
// new->menu_handle = CreatePopupMenu();
// AppendMenu( m->menu_handle, MF_ENABLED | MF_POPUP, new->menu_handle, name );
new->menu_handle = NULL;
new->item_head = NULL;
new->item_tail = NULL;
m->num_items += 1;
AddLLItemAtEnd( &m->item_head, &m->item_tail, (ss*)new );
return( new );
} /* addMenuToMenu */
/*
* add an item to a menu structure
*/
static item *addItemToMenu( menu *m, char *name, char *help, char *cmd,
bool append )
{
item *new;
int cmd_len;
int name_len;
// assert( IsMenu( m->menu_handle ) );
cmd_len = strlen( cmd );
name_len = strlen(name );
new = MemAlloc( sizeof( item ) + cmd_len + name_len + strlen( help ) + 2 );
if( *name == 0 ) {
new->id = 0;
new->name = NULL;
if( append ) {
AppendMenu( m->menu_handle, MF_SEPARATOR, 0, NULL );
}
} else {
strcpy( &new->cmd[0], cmd );
new->name = &new->cmd[ cmd_len + 1 ];
strcpy( new->name, name );
new->help = &new->name[ name_len + 1 ];
strcpy( new->help, help );
new->id = NextMenuId();
if( append ) {
AppendMenu( m->menu_handle, MF_ENABLED | MF_STRING, new->id, name );
}
}
new->in_menu = FALSE;
new->is_checked = FALSE;
new->is_active = TRUE;
m->num_items += 1;
AddLLItemAtEnd( &m->item_head, &m->item_tail, (ss*)new );
return( new );
} /* addItemToMenu */
/*
* findItem - look for a menu item with a particular offset
*/
static item *findItem( menu *m, int offset )
{
item *citem;
int i;
if( offset == -1 ) {
citem = m->item_tail;
} else {
citem = m->item_head;
for( i = 0; i < offset; i++ ) {
citem = citem->next;
if( citem == NULL ) {
break;
}
}
}
return( citem );
} /* findItem */
/*
* findMenu - look for a menu with a particular name
*/
static menu *findMenu( menu *parent, char *name )
{
menu *m;
m = specialMenu( name );
if( m == NULL ) {
for( m = (menu *)parent->item_head; m != NULL; m = m->next ) {
if( compareName( &m->name[ 0 ], name ) ) {
/* yep, this is him officer */
break;
}
}
}
return( m );
} /* findMenu */
/*
* freeItem - free an item in a menu
*/
static int freeItem( menu *m, int offset )
{
item *citem;
if( offset == -1 ) {
offset = m->num_items - 1;
}
citem = findItem( m, offset );
if( citem != NULL ) {
if( citem->in_menu ) {
assert( m->menu_handle != NULL );
DeleteMenu( m->menu_handle, offset, MF_BYPOSITION );
}
m->num_items -= 1;
DeleteLLItem( &m->item_head, &m->item_tail, (ss*)citem );
MemFree( citem );
return( TRUE );
}
return( FALSE );
} /* freeItem */
/*
* clearMenu - clear all items from a menu
*/
static void clearMenu( menu *m )
{
assert( m != NULL );
while( m->num_items > 0 ) {
freeItem( m, 0 );
}
assert( m->item_head == NULL );
} /* clearMenu */
/*
* burnItem - remove an item from a menu
*/
static void burnItem( menu *parent, int offset )
{
item *citem;
if( offset == -1 ) {
offset = parent->num_items - 1;
}
citem = findItem( parent, offset );
if( citem != NULL ) {
assert( parent->menu_handle != NULL );
DeleteMenu( parent->menu_handle, offset, MF_BYPOSITION );
citem->in_menu = FALSE;
}
} /* burnItem */
/*
* burnMenu - delete all menu items associated with menu
*/
static void burnMenu( menu *parent, menu *m )
{
int i;
if( m->menu_handle ) {
for( i = 0; i < m->num_items; i++ ) {
burnItem( m, i );
}
assert( parent->menu_handle != NULL );
for( i = 0; i < parent->num_items; i++ ) {
if( GetSubMenu( parent->menu_handle, i ) == m->menu_handle ) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?