/*------------------------------------------------------------*/ /* filename - tmnuview.cpp */ /* */ /* function(s) */ /* TMenuView member functions */ /*------------------------------------------------------------*/ /*------------------------------------------------------------*/ /* */ /* Turbo Vision - Version 1.0 */ /* */ /* */ /* Copyright (c) 1991 by Borland International */ /* All Rights Reserved. */ /* */ /*------------------------------------------------------------*/ #define Uses_TProgram #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 ) { TPoint mouse = makeLocal( e.mouse.where ); for( current = menu->items; current != 0; current = current->next ) { TRect r = getItemRect( current ); if( r.contains(mouse) ) 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; current = menu->deflt; TProgram::set_event_delay(0); do { action = doNothing; getEvent(e); switch (e.what) { case evMouseDown: if( mouseInView(e.mouse.where) || mouseInOwner(e) ) { trackMouse(e); if( size.y == 1 ) autoSelect = True; } else action = doReturn; break; case evMouseUp: trackMouse(e); if( mouseInOwner(e) ) current = menu->deflt; else if( current != 0 && current->name != 0 ) action = doSelect; else action = doReturn; break; case evMouseMove: if( e.mouse.buttons != 0 ) { trackMouse(e); 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 // ???? may be 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(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) == uchar(toupper(loc[1])) ) // ig 04.01.96 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; } uchar TMenuView::updateMenu( TMenu *menu ) { if ( !menu ) return False; uchar res = 2; for( TMenuItem *p = menu->items; p != 0; p = p->next ) { if ( p->name != 0 ) { if ( p->command == 0 ) { uchar rrr = updateMenu(p->subMenu); res |= (rrr & 1); p->disabled = Boolean((rrr & 2) != 0); } else { Boolean commandState = commandEnabled(p->command); if ( p->disabled == commandState ) { p->disabled = Boolean(!commandState); res |= 1; } } if ( !p->disabled ) res &= ~2; } } 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) & 1 ) drawView(); } break; } } TMenuItem *TMenuView::findHotKey( TMenuItem *p, ushort keyCode ) { while( p != 0 ) { if( p->name != 0 ) if( p->command == 0 ) { TMenuItem *T; if( (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 ); } #ifndef NO_TV_STREAMS void TMenuView::writeMenu( opstream& os, TMenu *menu ) { uchar tok = 0xFF; 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); TMenuItem *item = 0; uchar tok; is >> tok; while( tok != 0 ) { assert( tok == 0xFF ); 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 // ifndef NO_TV_STREAMS