From Tim.Buxton@um.cc.umich.edu Fri Jun 19 16:59:21 1992
Received: by E40-PO.MIT.EDU (5.45/4.7) id AA06323; Fri, 19 Jun 92 16:58:13 EDT
Received: from InterViews.Stanford.EDU by Athena.MIT.EDU with SMTP
	id AA13370; Fri, 19 Jun 92 16:58:08 EDT
Received: by interviews.Stanford.EDU (5.57/Ultrix3.0-C)
	id AA21255; Fri, 19 Jun 92 13:59:23 PDT
Received: by interviews.Stanford.EDU (5.57/Ultrix3.0-C)
	id AA21175; Fri, 19 Jun 92 13:58:31 PDT
Received: by lurch.Stanford.EDU (5.57/Ultrix2.4-C)
	id AA27612; Fri, 19 Jun 92 13:56:47 PDT
Received: by shelby.Stanford.EDU (5.57/Ultrix3.0-C)
	id AA19154; Fri, 19 Jun 92 13:33:52 -0700
Received: from um.cc.umich.edu by mailrus.cc.umich.edu (5.65/1123-1.0)
	id AA14707; Fri, 19 Jun 92 16:35:06 -0400
Date: Fri, 19 Jun 92 16:33:38 EDT
From: Tim.Buxton@um.cc.umich.edu
To: comp-windows-interviews@shelby.stanford.edu
Message-Id: <14288581@um.cc.umich.edu>
X-Mts-Userid: IEAR
Subject: Traveling Menu in IV -- Example code
SUB: Traveling Menu in IV -- Example code
SUM: Tim.Buxton@um.cc.umich.edu->comp-windows-interviews@shelby.stanford.edu

Hi!
 
Two weeks ago, we inquired on this newsgroup if there was a way to
implement "Traveling" menus that pop up where the mouse cursor is
at the time.  We wrote the following code to accomplish this and are
sending it out because it seems useful and instructive.
 
---------------------------------------  Cut Here  -------------------------------
// InterViews example code
// -----------------------
//   This code demonstrates a simple class called TravelingMenuPopup. 
// TravelingMenuPopup can be "wrapped" around a Glyph so that the 
// glyph, when clicked on, will have a menu pop up underneath the
// pointer (the wrapping is possible because InputHandler is derived
// from MonoGlyph, see the InterViews manual for information on the
// class MonoGlyph).  Dragging the pointer over the menu allows
// selection of the menu items (as usual).
//   A TravelingMenuPopup instance is constructed from a Glyph (which
// will become the body of the TravelingMenuPopup), a Menu, and a
// Style.  Therefore, to use this class, you must build the Glyph (or
// PolyGlyph) and the Menu before constructing a TravelingMenuPopup.
//
// This file can either be compiled as a single file or broken into
// component files as indicated by the comment lines dividing the 
// code.  The '#define _one_file_' simply keeps the compiler from 
// looking for the TravelingMenuPopup.h and SampleMenu.h header
// files should you decide to compile this code as one file.  If
// you break this file into its components DO NOT define _one_file_
// (or better yet remove the #ifndef's that look at _one_file_).
//
// Copyright  (c) 1992   OptiMetrics, Inc. Ann Arbor MI / Peter A. Seegers
//  Code may be freely used for any purpose
//
//
 
#define _one_file_
 
 
//--------------------------------------------------------------------
// TravelingMenuPopup.h
//--------------------------------------------------------------------
 
#ifndef _TRAVELINGMENUPOPUPHEADER_
#define _TRAVELINGMENUPOPUPHEADER_
 
#include <InterViews/handler.h>
#include <InterViews/event.h>
#include <InterViews/window.h>
#include <IV-look/menu.h>
 
class TravelingMenuPopup : public InputHandler
{
public:
                    TravelingMenuPopup( Glyph *, Menu *, Style * );
 
    virtual void    press( const Event & );
    virtual void    drag( const Event & );
    virtual void    release( const Event & );
private:
    PopupWindow     *popupWindow;
    Menu            *mainMenu;
};
 
 
#endif
 
//--------------------------------------------------------------------
// TravelingMenuPopup.c++
//--------------------------------------------------------------------
 
#ifndef _one_file_
#include "TravelingMenuPopup.h"
#endif
 
#include <stream.h>
 
TravelingMenuPopup::TravelingMenuPopup( Glyph *body, Menu *menu, Style *style )
    : InputHandler( body, style )
{
    popupWindow = new PopupWindow( menu );
    mainMenu = menu;
}
 
void TravelingMenuPopup::press( const Event &testEvent )
{
    Coord lower_x = testEvent.pointer_x();
    Coord lower_y = testEvent.pointer_y();
 
    // Place the window . . . remembering that testEvent
    //  returns coordinates relative to the window's lower
    //  left corner, while popupWindow->place() deals in 
    //  display coordinates (i.e. relative to the lower left
    //  corner of the screen).
 
    popupWindow->place( lower_x + testEvent.window()->left(),
                        lower_y + testEvent.window()->bottom() );
 
    // Set the alignment so the window is places from
    //  the upper left corner.
 
    popupWindow->align( 0, 1 );
 
    popupWindow->map();
 
    // Remember, since the popupWindow is NOT a managed window
    //  (i.e. the window manager doesn't know it exists) it's
    //  your responsibility to pass events through to the menu
    //  that's inside the popupWindow.
 
    mainMenu->press( testEvent );
}
 
void TravelingMenuPopup::drag( const Event &testEvent )
{
    // Remember, since the popupWindow is NOT a managed window
    //  (i.e. the window manager doesn't know it exists) it's
    //  your responsibility to pass events through to the menu
    //  that's inside the popupWindow.
 
    mainMenu->drag( testEvent ); 
}
 
void TravelingMenuPopup::release( const Event &testEvent )
{
    // Remember, since the popupWindow is NOT a managed window
    //  (i.e. the window manager doesn't know it exists) it's
    //  your responsibility to pass events through to the menu
    //  that's inside the popupWindow.
 
    mainMenu->release( testEvent );
 
    popupWindow->unmap();
}
 
//--------------------------------------------------------------------
// SampleMenu.h
//--------------------------------------------------------------------
 
#ifndef _CONNECTIONMENUH_
#define _CONNECTIONMENUH_
 
#include <InterViews/event.h>
#include <InterViews/window.h>
#include <InterViews/handler.h>
#include <InterViews/action.h>
#include <IV-look/menu.h>
 
 
class SampleMenu;
 
declareActionCallback(SampleMenu);
 
struct SampleCmdInfo {
    const char* str;
    ActionMemberFunction(SampleMenu)* func;
    SampleCmdInfo* submenu;
    int options;
};
 
class SampleMenu : public Menu
{
public:
            SampleMenu();
    void    press( const Event & );
    void    drag( const Event & );
    void    release( const Event & );
private:
    Menu    *travelingPulldown;
 
    static  SampleCmdInfo SamplePulldownInfo[4];
 
    void    quit();
    void    information();
    void    moreInformation();
};
 
 
 
#endif
 
//--------------------------------------------------------------------
// SampleMenu.c++
//--------------------------------------------------------------------
 
#include <stream.h>
 
#include <InterViews/window.h>
#include <InterViews/style.h>
#include <InterViews/session.h>
#include <IV-look/kit.h>
#include <InterViews/layout.h>
 
#ifndef _one_file_
#include "SampleMenu.h"
#endif
 
 
SampleCmdInfo SampleMenu::SamplePulldownInfo[4] = {
        { "Quit",  &SampleMenu::quit }, 
        { "Information",  &SampleMenu::information }, 
        { "More Information",  &SampleMenu::moreInformation }, 
        { nil } 
        };
 
 
implementActionCallback( SampleMenu );
 
SampleMenu::SampleMenu()
    : Menu( travelingPulldown = WidgetKit::instance()->pulldown(),
            WidgetKit::instance()->style(), 0, 0, 0, 0 )
{
    WidgetKit   *kit = WidgetKit::instance();
    LayoutKit   *layout = LayoutKit::instance();
 
    // travelingPulldown = kit->pulldown();
 
    for (SampleCmdInfo* i = SamplePulldownInfo; i->str != nil; i++) 
        {
        if( i->str[0] == '\0' )
            {
            travelingPulldown->append_item(kit->menu_item_separator());
            } 
        else 
            {
            //  The RMargin makes the highlighted portion of the menu item
            //  extend to the right edge of the pulldown part of the menu 
            //  rather than surrounding the menu item as closely as possible.
 
            Glyph   *g = layout->r_margin(kit->label(i->str), 0.0, fil, 0.0);
            MenuItem *mi= kit->menu_item(g);
 
            travelingPulldown->append_item(mi);
            mi->action( new ActionCallback(SampleMenu)(this, i->func));
            }
        }
}
 
void SampleMenu::press( const Event &e )
{
    travelingPulldown->press( e );
}
 
void SampleMenu::drag( const Event &e )
{
    travelingPulldown->drag( e );
}
 
void SampleMenu::release( const Event &e )
{
    travelingPulldown->release( e );
}
 
 
void SampleMenu::quit() { Session::instance()->quit(); }
void SampleMenu::information()   { printf( "Information\n" ); }
void SampleMenu::moreInformation() { printf( "More Information\n" ); }
 
 
//--------------------------------------------------------------------
// main.c++
//--------------------------------------------------------------------
 
 
#include <IV-look/kit.h>
#include <InterViews/background.h>
#include <InterViews/session.h>
#include <InterViews/style.h>
#include <InterViews/layout.h>
#include <InterViews/window.h>
#include <InterViews/handler.h>
 
#ifndef _one_file_
#include "TravelingMenuPopup.h"
#include "SampleMenu.h"
#endif
 
 
 
int main(int argc, char** argv) 
{
    Session     *session = new Session("TravelingMenu", argc, argv);
    WidgetKit   *kit = WidgetKit::instance();
    LayoutKit   *layout = LayoutKit::instance();
 
    Glyph       *mainArea = new TravelingMenuPopup(
                                        layout->vbox(
                                            layout->vglue(500, fil, fil),
                                            layout->hglue(500, fil, fil) ),
                                        new SampleMenu(),
                                        kit->style() );
 
    return session->run_window(
        new ApplicationWindow(
            kit->inset_frame( mainArea )
        )
    );
}
 
---------------------------------  End of Code  ---------------------------------
 
Enjoy!
 
Peter Seegers
 
OptiMetrics, Inc.
Ann Arbor, MI

