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 + -
显示快捷键?