/* * TMenuView.cc * * Turbo Vision - Version 2.0 * * Copyright (c) 1994 by Borland International * All Rights Reserved. * * Modified by Sergio Sigala */ #define Uses_TMenuItem #define Uses_TMenu #define Uses_TMenuView #define Uses_TKeys #define Uses_TRect #define Uses_TEvent #define Uses_TGroup #define Uses_TMenuBox #define Uses_opstream #define Uses_ipstream #include #include #include #include #define cpMenuView "\x02\x03\x04\x05\x06\x07" TMenuItem::TMenuItem( const char *aName, ushort aCommand, ushort aKeyCode, ushort aHelpCtx, char *p, TMenuItem *aNext ) { name = newStr( aName ); command = aCommand; disabled = Boolean(!TView::commandEnabled(command)); keyCode = aKeyCode; helpCtx = aHelpCtx; if( p == 0 ) param = 0; else param = newStr( p ); next = aNext; } TMenuItem::TMenuItem( const char *aName, ushort aKeyCode, TMenu *aSubMenu, ushort aHelpCtx, TMenuItem *aNext ) { name = newStr( aName ); command = 0; disabled = Boolean(!TView::commandEnabled(command)); keyCode = aKeyCode; helpCtx = aHelpCtx; subMenu = aSubMenu; next = aNext; } TMenuItem::~TMenuItem() { delete (char *)name; if( command == 0 ) delete subMenu; else delete (char *)param; } TMenu::~TMenu() { while( items != 0 ) { TMenuItem *temp = items; items = items->next; delete temp; } } void TMenuView::trackMouse( TEvent& e, Boolean& mouseActive ) { TPoint mouse = makeLocal( e.mouse.where ); for( current = menu->items; current != 0; current = current->next ) { TRect r = getItemRect( current ); if( r.contains(mouse) ) { mouseActive = True; return; } } } void TMenuView::nextItem() { if( (current = current->next) == 0 ) current = menu->items; } void TMenuView::prevItem() { TMenuItem *p; if( (p = current) == menu->items) p = 0; do { nextItem(); } while( current->next != p ); } void TMenuView::trackKey( Boolean findNext ) { if( current == 0 ) return; do { if( findNext ) nextItem(); else prevItem(); } while( current->name == 0 ); } Boolean TMenuView::mouseInOwner( TEvent& e ) { if( parentMenu == 0 || parentMenu->size.y != 1 ) return False; else { TPoint mouse = parentMenu->makeLocal( e.mouse.where ); TRect r = parentMenu->getItemRect( parentMenu->current ); return r.contains( mouse ); } } Boolean TMenuView::mouseInMenus( TEvent& e ) { TMenuView *p = parentMenu; while( p != 0 && !p->mouseInView(e.mouse.where) ) p = p->parentMenu; return Boolean( p != 0 ); } TMenuView *TMenuView::topMenu() { TMenuView *p = this; while( p->parentMenu != 0 ) p = p->parentMenu; return p; } enum menuAction { doNothing, doSelect, doReturn }; ushort TMenuView::execute() { Boolean autoSelect = False; menuAction action; char ch; ushort result = 0; TMenuItem *itemShown = 0; TMenuItem *p; TMenuView *target; TRect r; TEvent e; Boolean mouseActive; current = menu->deflt; mouseActive = False; do { action = doNothing; getEvent(e); switch (e.what) { case evMouseDown: if( mouseInView(e.mouse.where) || mouseInOwner(e) ) { trackMouse(e, mouseActive); if( size.y == 1 ) autoSelect = True; } else action = doReturn; break; case evMouseUp: trackMouse(e, mouseActive); if( mouseInOwner(e) ) current = menu->deflt; else if( current != 0 && current->name != 0 ) action = doSelect; else if (mouseActive) action = doReturn; else { current = menu->deflt; if (current == 0) current = menu->items; action = doNothing; } break; case evMouseMove: if( e.mouse.buttons != 0 ) { trackMouse(e, mouseActive); if( !(mouseInView(e.mouse.where) || mouseInOwner(e)) && mouseInMenus(e) ) action = doReturn; } break; case evKeyDown: switch( ctrlToArrow(e.keyDown.keyCode) ) { case kbUp: case kbDown: if( size.y != 1 ) trackKey(Boolean(ctrlToArrow(e.keyDown.keyCode) == kbDown)); else if( e.keyDown.keyCode == kbDown ) autoSelect = True; break; case kbLeft: case kbRight: if( parentMenu == 0 ) trackKey(Boolean(ctrlToArrow(e.keyDown.keyCode) == kbRight)); else action = doReturn; break; case kbHome: case kbEnd: if( size.y != 1 ) { current = menu->items; if( e.keyDown.keyCode == kbEnd ) trackKey(False); } break; case kbEnter: if( size.y == 1 ) autoSelect = True; action = doSelect; break; case kbEsc: action = doReturn; if( parentMenu == 0 || parentMenu->size.y != 1 ) clearEvent(e); break; default: target = this; ch = getAltChar(e.keyDown.keyCode); if( ch == 0 ) ch = e.keyDown.charScan.charCode; else target = topMenu(); p = target->findItem(ch); if( p == 0 ) { p = topMenu()->hotKey(e.keyDown.keyCode); if( p != 0 && commandEnabled(p->command) ) { result = p->command; action = doReturn; } } else if( target == this ) { if( size.y == 1 ) autoSelect = True; action = doSelect; current = p; } else if( parentMenu != target || parentMenu->current != p ) action = doReturn; } break; case evCommand: if( e.message.command == cmMenu ) { autoSelect = False; if (parentMenu != 0 ) action = doReturn; } else action = doReturn; break; } if( itemShown != current ) { itemShown = current; drawView(); } if( (action == doSelect || (action == doNothing && autoSelect)) && current != 0 && current->name != 0 ) if( current->command == 0 ) { if( (e.what & (evMouseDown | evMouseMove)) != 0 ) putEvent(e); r = getItemRect( current ); r.a.x = r.a.x + origin.x; r.a.y = r.b.y + origin.y; r.b = owner->size; if( size.y == 1 ) r.a.x--; target = topMenu()->newSubView(r, current->subMenu,this); result = owner->execView(target); destroy( target ); } else if( action == doSelect ) result = current->command; if( result != 0 && commandEnabled(result) ) { action = doReturn; clearEvent(e); } else result = 0; } while( action != doReturn ); if( e.what != evNothing && (parentMenu != 0 || e.what == evCommand)) putEvent(e); if( current != 0 ) { menu->deflt = current; current = 0; drawView(); } return result; } TMenuItem *TMenuView::findItem( char ch ) { ch = toupper((uchar)ch); TMenuItem *p = menu->items; while( p != 0 ) { if( p->name != 0 && !p->disabled ) { char *loc = strchr( (char *) p->name, '~' ); if( loc != 0 && (uchar)ch == toupper( (uchar)(loc[1]) ) ) return p; } p = p->next; } return 0; } TRect TMenuView::getItemRect( TMenuItem * ) { return TRect( 0, 0, 0, 0 ); } ushort TMenuView::getHelpCtx() { TMenuView *c = this; while( c != 0 && (c->current == 0 || c->current->helpCtx == hcNoContext || c->current->name == 0 ) ) c = c->parentMenu; if( c != 0 ) return c->current->helpCtx; else return hcNoContext; } TPalette& TMenuView::getPalette() const { static TPalette palette( cpMenuView, sizeof( cpMenuView )-1 ); return palette; } Boolean TMenuView::updateMenu( TMenu *menu ) { Boolean res = False; if( menu != 0 ) { for( TMenuItem *p = menu->items; p != 0; p = p->next ) { if( p->name != 0 ) if( p->command == 0 ) { if( p->subMenu && updateMenu(p->subMenu) == True ) res = True; } else { Boolean commandState = commandEnabled(p->command); if( p->disabled == commandState ) { p->disabled = Boolean(!commandState); res = True; } } } } return res; } void TMenuView::do_a_select( TEvent& event ) { putEvent( event ); event.message.command = owner->execView(this); if( event.message.command != 0 && commandEnabled(event.message.command) ) { event.what = evCommand; event.message.infoPtr = 0; putEvent(event); } clearEvent(event); } void TMenuView::handleEvent( TEvent& event ) { if( menu != 0 ) switch (event.what) { case evMouseDown: do_a_select(event); break; case evKeyDown: if( findItem(getAltChar(event.keyDown.keyCode)) != 0 ) do_a_select(event); else { TMenuItem *p = hotKey(event.keyDown.keyCode); if( p != 0 && commandEnabled(p->command)) { event.what = evCommand; event.message.command = p->command; event.message.infoPtr = 0; putEvent(event); clearEvent(event); } } break; case evCommand: if( event.message.command == cmMenu ) do_a_select(event); break; case evBroadcast: if( event.message.command == cmCommandSetChanged ) { if( updateMenu(menu) ) drawView(); } break; } } TMenuItem *TMenuView::findHotKey( TMenuItem *p, ushort keyCode ) { while( p != 0 ) { if( p->name != 0 ) if( p->command == 0 ) { TMenuItem *T; if( p->subMenu != 0 && (T = findHotKey( p->subMenu->items, keyCode )) != 0 ) return T; } else if( !p->disabled && p->keyCode != kbNoKey && p->keyCode == keyCode ) return p; p = p->next; } return 0; } TMenuItem *TMenuView::hotKey( ushort keyCode ) { return findHotKey( menu->items, keyCode ); } TMenuView *TMenuView::newSubView( const TRect& bounds, TMenu *aMenu, TMenuView *aParentMenu ) { return new TMenuBox( bounds, aMenu, aParentMenu ); } #if !defined(NO_STREAMABLE) void TMenuView::writeMenu( opstream& os, TMenu *menu ) { uchar tok = 0xFF; assert( menu != 0 ); for( TMenuItem *item = menu->items; item != 0; item = item->next ) { os << tok; os.writeString( item->name ); os << item->command << (int)(item->disabled) << item->keyCode << item->helpCtx; if( item->name != 0 ) { if( item->command == 0 ) writeMenu( os, item->subMenu ); else os.writeString( item->param ); } } tok = 0; os << tok; } void TMenuView::write( opstream& os ) { TView::write( os ); writeMenu( os, menu ); } TMenu *TMenuView::readMenu( ipstream& is ) { TMenu *menu = new TMenu; TMenuItem **last = &(menu->items); #ifndef __UNPATCHED TMenuItem *item; #else TMenuItem *item = 0; #endif uchar tok; is >> tok; while( tok != 0 ) { assert( tok == 0xFF ); /* SS: this line gave problems with egcs-1.0.3 */ item = new TMenuItem( (char *)0, 0, (TMenu *)0 ); *last = item; last = &(item->next); item->name = is.readString(); int temp; is >> item->command >> temp >> item->keyCode >> item->helpCtx; item->disabled = Boolean( temp ); if( item->name != 0 ) { if( item->command == 0 ) item->subMenu = readMenu( is ); else item->param = is.readString(); } is >> tok; } *last = 0; menu->deflt = menu->items; return menu; } void *TMenuView::read( ipstream& is ) { TView::read( is ); menu = readMenu( is ); parentMenu = 0; current = 0; return this; } TStreamable *TMenuView::build() { return new TMenuView( streamableInit ); } TMenuView::TMenuView( StreamableInit ) : TView( streamableInit ) { } #endif