home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tv20os2.zip / src / TMenuView.cpp < prev    next >
C/C++ Source or Header  |  1999-05-26  |  16KB  |  613 lines

  1. /*
  2.  * TMenuView.cc
  3.  *
  4.  * Turbo Vision - Version 2.0
  5.  *
  6.  * Copyright (c) 1994 by Borland International
  7.  * All Rights Reserved.
  8.  *
  9.  * Modified by Sergio Sigala <ssigala@globalnet.it>
  10.  */
  11.  
  12. #define Uses_MsgBox
  13. #define Uses_TMenuItem
  14. #define Uses_TMenu
  15. #define Uses_TMenuView
  16. #define Uses_TKeys
  17. #define Uses_TRect
  18. #define Uses_TEvent
  19. #define Uses_TGroup
  20. #define Uses_TMenuBox
  21. #define Uses_opstream
  22. #define Uses_ipstream
  23. #include <tvision/tv.h>
  24.  
  25. #include <assert.h>
  26. #include <ctype.h>
  27. #include <string.h>
  28.  
  29. #define cpMenuView "\x02\x03\x04\x05\x06\x07"
  30.  
  31. TMenuItem::TMenuItem(   const char *aName,
  32.                         ushort aCommand,
  33.                         ushort aKeyCode,
  34.                         ushort aHelpCtx,
  35.                         char *p,
  36.                         TMenuItem *aNext
  37.              )
  38. {
  39.     name = newStr( aName );
  40.     command = aCommand;
  41.     disabled = Boolean(!TView::commandEnabled(command));
  42.     keyCode = aKeyCode;
  43.     helpCtx = aHelpCtx;
  44.     if( p == 0 )
  45.         param = 0;
  46.     else
  47.         param = newStr( p );
  48.     next = aNext;
  49. }
  50.  
  51. TMenuItem::TMenuItem( const char *aName,
  52.                       ushort aKeyCode,
  53.                       TMenu *aSubMenu,
  54.                       ushort aHelpCtx,
  55.                       TMenuItem *aNext
  56.                     )
  57. {
  58.     name = newStr( aName );
  59.     command = 0;
  60.     disabled = Boolean(!TView::commandEnabled(command));
  61.     keyCode = aKeyCode;
  62.     helpCtx = aHelpCtx;
  63.     subMenu = aSubMenu;
  64.     next = aNext;
  65. }
  66.  
  67. TMenuItem::~TMenuItem()
  68. {
  69.     delete (char *)name;
  70.     if( command == 0 )
  71.         delete subMenu;
  72.     else
  73.         delete (char *)param;
  74. }
  75.  
  76. TMenu::~TMenu()
  77. {
  78.     while( items != 0 )
  79.         {
  80.         TMenuItem *temp = items;
  81.         items = items->next;
  82.         delete temp;
  83.         }
  84. }
  85.  
  86. void TMenuView::trackMouse( TEvent& e, Boolean& mouseActive )
  87. {
  88.     TPoint mouse = makeLocal( e.mouse.where );
  89.     for( current = menu->items; current != 0; current = current->next )
  90.         {
  91.         TRect r = getItemRect( current );
  92.         if( r.contains(mouse) )
  93.         {
  94.         mouseActive = True;
  95.             return;
  96.         }
  97.         }
  98. }
  99.  
  100. void TMenuView::nextItem()
  101. {
  102.     if( (current = current->next) == 0 )
  103.         current = menu->items;
  104. }
  105.  
  106. void TMenuView::prevItem()
  107. {
  108.     TMenuItem *p;
  109.  
  110.     if( (p = current) == menu->items)
  111.         p = 0;
  112.  
  113.     do  {
  114.         nextItem();
  115.         } while( current->next != p );
  116. }
  117.  
  118. void TMenuView::trackKey( Boolean findNext )
  119. {
  120.     if( current == 0 )
  121.         return;
  122.  
  123.     do  {
  124.         if( findNext )
  125.             nextItem();
  126.         else
  127.             prevItem();
  128.         } while( current->name == 0 );
  129. }
  130.  
  131. Boolean TMenuView::mouseInOwner( TEvent& e )
  132. {
  133.     if( parentMenu == 0 || parentMenu->size.y != 1 )
  134.         return False;
  135.     else
  136.         {
  137.         TPoint mouse = parentMenu->makeLocal( e.mouse.where );
  138.         TRect r = parentMenu->getItemRect( parentMenu->current );
  139.         return r.contains( mouse );
  140.         }
  141. }
  142.  
  143. Boolean TMenuView::mouseInMenus( TEvent& e )
  144. {
  145.     TMenuView *p =  parentMenu;
  146.     while( p != 0 && !p->mouseInView(e.mouse.where) )
  147.         p = p->parentMenu;
  148.  
  149.     return Boolean( p != 0 );
  150. }
  151.  
  152. TMenuView *TMenuView::topMenu()
  153. {
  154.     TMenuView *p = this;
  155.     while( p->parentMenu != 0 )
  156.         p = p->parentMenu;
  157.     return p;
  158. }
  159.  
  160. enum menuAction { doNothing, doSelect, doReturn };
  161.  
  162. ushort TMenuView::execute()
  163. {
  164.     Boolean    autoSelect = False;
  165.     menuAction action;
  166.     char   ch;
  167.     ushort result = 0;
  168.     TMenuItem *itemShown = 0;
  169.     TMenuItem *p;
  170.     TMenuView *target;
  171.     TRect  r;
  172.     TEvent e;
  173.     Boolean mouseActive;
  174.  
  175.     current = menu->deflt;
  176.     mouseActive = False;
  177.     do  {
  178.         action = doNothing;
  179.         getEvent(e);
  180.         switch (e.what)
  181.             {
  182.             case  evMouseDown:
  183.                 if( mouseInView(e.mouse.where) || mouseInOwner(e) )
  184.                     {
  185.                     trackMouse(e, mouseActive);
  186.                     if( size.y == 1 )
  187.                         autoSelect = True;
  188.                     }
  189.                 else
  190.                     action =  doReturn;
  191.                 break;
  192.             case  evMouseUp:
  193.                 trackMouse(e, mouseActive);
  194.                 if( mouseInOwner(e) )
  195.                     current = menu->deflt;
  196.                 else if( current != 0 && current->name != 0 )
  197.                     action = doSelect;
  198.                 else if (mouseActive)
  199.                     action = doReturn;
  200.         else
  201.             {
  202.             current = menu->deflt;
  203.             if (current == 0)
  204.                 current = menu->items;
  205.             action = doNothing;
  206.             }
  207.                 break;
  208.             case  evMouseMove:
  209.                 if( e.mouse.buttons != 0 )
  210.                     {
  211.                     trackMouse(e, mouseActive);
  212.                     if( !(mouseInView(e.mouse.where) || mouseInOwner(e)) &&
  213.                         mouseInMenus(e) )
  214.                         action = doReturn;
  215.                     }
  216.                 break;
  217.             case  evKeyDown:
  218.                 switch( ctrlToArrow(e.keyDown.keyCode) )
  219.                     {
  220.                     case  kbUp:
  221.                     case  kbDown:
  222. //    messageBox( "1!!!", mfError | mfOKButton );
  223.                         if( size.y != 1 )
  224.                             trackKey(Boolean(ctrlToArrow(e.keyDown.keyCode) == kbDown));
  225.                         else if( e.keyDown.keyCode == kbDown )
  226.                             autoSelect =  True;
  227.                         break;
  228.                     case  kbLeft:
  229.                     case  kbRight:
  230.                         if( parentMenu == 0 )
  231.                             trackKey(Boolean(ctrlToArrow(e.keyDown.keyCode) == kbRight));
  232.                         else
  233.                             action =  doReturn;
  234.                         break;
  235.                     case  kbHome:
  236.                     case  kbEnd:
  237.                         if( size.y != 1 )
  238.                             {
  239.                             current = menu->items;
  240.                             if( e.keyDown.keyCode == kbEnd )
  241.                                 trackKey(False);
  242.                             }
  243.                         break;
  244.                     case  kbEnter:
  245.                         if( size.y == 1 )
  246.                             autoSelect =  True;
  247.                         action = doSelect;
  248.                         break;
  249.                     case  kbEsc:
  250.                         action = doReturn;
  251.                         if( parentMenu == 0 || parentMenu->size.y != 1 )
  252.                             clearEvent(e);
  253.                         break;
  254.                     default:
  255.                         target = this;
  256.                         ch = getAltChar(e.keyDown.keyCode);
  257.                         if( ch == 0 )
  258.                             ch = e.keyDown.charScan.charCode;
  259.                         else
  260.                             target = topMenu();
  261.                         p = target->findItem(ch);
  262.                         if( p == 0 )
  263.                             {
  264.                             p = topMenu()->hotKey(e.keyDown.keyCode);
  265.                             if( p != 0 && commandEnabled(p->command) )
  266.                                 {
  267.                                 result = p->command;
  268.                                 action = doReturn;
  269.                                 }
  270.                             }
  271.                         else if( target == this )
  272.                             {
  273.                             if( size.y == 1 )
  274.                                 autoSelect = True;
  275.                             action = doSelect;
  276.                             current = p;
  277.                             }
  278.                         else if( parentMenu != target ||
  279.                                  parentMenu->current != p )
  280.                                 action = doReturn;
  281.                     }
  282.                 break;
  283.             case  evCommand:
  284.                 if( e.message.command == cmMenu )
  285.                     {
  286.                     autoSelect = False;
  287.                     if (parentMenu != 0 )
  288.                         action = doReturn;
  289.                     }
  290.                 else
  291.                     action = doReturn;
  292.                 break;
  293.             }
  294.  
  295.         if( itemShown != current )
  296.             {
  297.             itemShown =  current;
  298.             drawView();
  299.             }
  300.  
  301.         if( (action == doSelect || (action == doNothing && autoSelect)) &&
  302.             current != 0 &&
  303.             current->name != 0 )
  304.                 if( current->command == 0 )
  305.                     {
  306.                     if( (e.what & (evMouseDown | evMouseMove)) != 0 )
  307.                         putEvent(e);
  308.                     r = getItemRect( current );
  309.                     r.a.x = r.a.x + origin.x;
  310.                     r.a.y = r.b.y + origin.y;
  311.                     r.b = owner->size;
  312.                     if( size.y == 1 )
  313.                         r.a.x--;
  314.                     target = topMenu()->newSubView(r, current->subMenu,this);
  315.                     result = owner->execView(target);
  316.                     destroy( target );
  317.                     }
  318.                 else if( action == doSelect )
  319.                     result = current->command;
  320.  
  321.         if( result != 0 && commandEnabled(result) )
  322.             {
  323.             action =  doReturn;
  324.             clearEvent(e);
  325.             }
  326.         else
  327.             result = 0;
  328.         } while( action != doReturn );
  329.  
  330.     if( e.what != evNothing &&
  331.         (parentMenu != 0 || e.what == evCommand))
  332.             putEvent(e);
  333.     if( current != 0 )
  334.         {
  335.         menu->deflt = current;
  336.         current = 0;
  337.         drawView();
  338.         }
  339.     return result;
  340. }
  341.  
  342. TMenuItem *TMenuView::findItem( char ch )
  343. {
  344. //Orlik
  345. char *Latin    ="qwertyuiop[]asdfghjkl;'zxcvbnm,.";
  346. char *RussianLC="⌐µπ¬Ñ¡úΦΘºσΩΣδóá»α«½ñªφ∩τß¼¿Γ∞íε";
  347. char *RussianUC="ëûôèàìâÿÖçòÜö¢éÇÅÉÄïä奃ùæîêÆ£ü₧";
  348. char *pos, ch2;
  349.  
  350. //Orlik
  351.     pos = strchr( RussianLC, ch );
  352.     if( pos ) ch = Latin[ pos - RussianLC ];
  353.     pos = strchr( RussianUC, ch );
  354.     if( pos ) ch = Latin[ pos - RussianUC ];    //Orlik
  355.    ch = toupper(ch);
  356.     TMenuItem *p = menu->items;
  357.     while( p != 0 )
  358.         {
  359.         if( p->name != 0 && !p->disabled )
  360.             {
  361.             char *loc = strchr( (char *) p->name, '~' );
  362.             if( loc != 0 )
  363.                 {
  364.                 ch2 = loc[1];    //Orlik
  365.                     pos = strchr( RussianLC, ch2 );
  366.                     if( pos ) ch2 = Latin[ pos - RussianLC ];
  367.                     pos = strchr( RussianUC, ch2 );
  368.                     if( pos ) ch2 = Latin[ pos - RussianUC ];    //Orlik
  369.                 if ((uchar)ch == toupper( ch2 ) )
  370. //                if ((uchar)ch == toupper( loc[1] ) )
  371.                     return p;
  372.                }
  373.             }
  374.         p =  p->next;
  375.         }
  376.     return 0;
  377. }
  378.  
  379. TRect TMenuView::getItemRect( TMenuItem * )
  380. {
  381.     return TRect( 0, 0, 0, 0 );
  382. }
  383.  
  384. ushort TMenuView::getHelpCtx()
  385. {
  386.     TMenuView *c = this;
  387.  
  388.     while( c != 0 &&
  389.                 (c->current == 0 ||
  390.                  c->current->helpCtx == hcNoContext ||
  391.                  c->current->name == 0 )
  392.          )
  393.         c = c->parentMenu;
  394.  
  395.     if( c != 0 )
  396.         return c->current->helpCtx;
  397.     else
  398.         return hcNoContext;
  399. }
  400.  
  401. TPalette& TMenuView::getPalette() const
  402. {
  403.     static TPalette palette( cpMenuView, sizeof( cpMenuView )-1 );
  404.     return palette;
  405. }
  406.  
  407. Boolean TMenuView::updateMenu( TMenu *menu )
  408. {
  409.     Boolean res = False;
  410.     if( menu != 0 )
  411.         {
  412.         for( TMenuItem *p = menu->items; p != 0; p = p->next )
  413.             {
  414.             if( p->name != 0 )
  415.                 if( p->command == 0 )
  416.                     {
  417.                     if( p->subMenu && updateMenu(p->subMenu) == True )
  418.                         res = True;
  419.                     }
  420.                 else
  421.                     {
  422.                     Boolean commandState = commandEnabled(p->command);
  423.                     if( p->disabled == commandState )
  424.                         {
  425.                         p->disabled = Boolean(!commandState);
  426.                         res = True;
  427.                         }
  428.                     }
  429.             }
  430.         }
  431.     return res;
  432. }
  433.  
  434. void TMenuView::do_a_select( TEvent& event )
  435. {
  436.     putEvent( event );
  437.     event.message.command = owner->execView(this);
  438.     if( event.message.command != 0 && commandEnabled(event.message.command) )
  439.         {
  440.         event.what = evCommand;
  441.         event.message.infoPtr = 0;
  442.         putEvent(event);
  443.         }
  444.     clearEvent(event);
  445. }
  446.  
  447. void TMenuView::handleEvent( TEvent& event )
  448. {
  449.     if( menu != 0 )
  450.         switch (event.what)
  451.             {
  452.             case  evMouseDown:
  453.                 do_a_select(event);
  454.                 break;
  455.             case  evKeyDown:
  456.                 if( findItem(getAltChar(event.keyDown.keyCode)) != 0 )
  457.                     do_a_select(event);
  458.                 else
  459.                     {
  460.                     TMenuItem *p = hotKey(event.keyDown.keyCode);
  461.                     if( p != 0 && commandEnabled(p->command))
  462.                         {
  463.                         event.what = evCommand;
  464.                         event.message.command = p->command;
  465.                         event.message.infoPtr = 0;
  466.                         putEvent(event);
  467.                         clearEvent(event);
  468.                         }
  469.                     }
  470.                 break;
  471.             case  evCommand:
  472.                 if( event.message.command == cmMenu )
  473.                     do_a_select(event);
  474.                 break;
  475.             case  evBroadcast:
  476.                 if( event.message.command == cmCommandSetChanged )
  477.                     {
  478.                     if( updateMenu(menu) )
  479.                         drawView();
  480.                     }
  481.                 break;
  482.             }
  483. }
  484.  
  485.  
  486. TMenuItem *TMenuView::findHotKey( TMenuItem *p, ushort keyCode )
  487. {
  488.  
  489.     while( p != 0 )
  490.         {
  491.         if( p->name != 0 )
  492.             if( p->command == 0 )
  493.                 {
  494.                 TMenuItem *T;
  495.                 if( (T = findHotKey( p->subMenu->items, keyCode )) != 0 )
  496.                     return T;
  497.                 }
  498.             else 
  499.                 if( !p->disabled &&
  500.                      p->keyCode != kbNoKey &&
  501.                      p->keyCode == keyCode
  502.                    )
  503.                 return p;
  504.         p =  p->next;
  505.         }
  506.     return 0;
  507. }
  508.  
  509. TMenuItem *TMenuView::hotKey( ushort keyCode )
  510. {
  511.     return findHotKey( menu->items, keyCode );
  512. }
  513.  
  514. TMenuView *TMenuView::newSubView( const TRect& bounds,
  515.                                   TMenu *aMenu,
  516.                                   TMenuView *aParentMenu
  517.                                )
  518. {
  519.     return new TMenuBox( bounds, aMenu, aParentMenu );
  520. }
  521.  
  522. #if !defined(NO_STREAMABLE)
  523.  
  524. void TMenuView::writeMenu( opstream& os, TMenu *menu )
  525. {
  526.     uchar tok = 0xFF;
  527.  
  528.     assert( menu != 0 );
  529.  
  530.     for( TMenuItem *item = menu->items; item != 0; item = item->next )
  531.         {
  532.         os << tok;
  533.         os.writeString( item->name );
  534.         os << item->command << (int)(item->disabled)
  535.            << item->keyCode << item->helpCtx;
  536.         if( item->name != 0 )
  537.             {
  538.             if( item->command == 0 )
  539.                 writeMenu( os, item->subMenu );
  540.             else
  541.                 os.writeString( item->param );
  542.             }
  543.         }
  544.  
  545.     tok = 0;
  546.     os << tok;
  547. }
  548.  
  549. void TMenuView::write( opstream& os )
  550. {
  551.     TView::write( os );
  552.     writeMenu( os, menu );
  553. }
  554.  
  555. TMenu *TMenuView::readMenu( ipstream& is )
  556. {
  557.     TMenu *menu = new TMenu;
  558.     TMenuItem **last = &(menu->items);
  559. #ifndef __UNPATCHED
  560.     TMenuItem *item;
  561. #else
  562.     TMenuItem *item = 0;
  563. #endif
  564.  
  565.     uchar tok;
  566.     is >> tok;
  567.  
  568.     while( tok != 0 )
  569.         {
  570.         assert( tok == 0xFF );
  571.         item = new TMenuItem( 0, 0, (void *)0 );
  572.         *last = item;
  573.         last = &(item->next);
  574.         item->name = is.readString();
  575.         int temp;
  576.         is >> item->command >> temp
  577.            >> item->keyCode >> item->helpCtx;
  578.         item->disabled = Boolean( temp );
  579.         if( item->name != 0 )
  580.             {
  581.             if( item->command == 0 )
  582.                 item->subMenu = readMenu( is );
  583.             else
  584.                 item->param = is.readString();
  585.             }
  586.         is >> tok;
  587.         }
  588.     *last = 0;
  589.     menu->deflt = menu->items;
  590.     return menu;
  591. }
  592.  
  593. void *TMenuView::read( ipstream& is )
  594. {
  595.     TView::read( is );
  596.     menu = readMenu( is );
  597.     parentMenu = 0;
  598.     current = 0;
  599.     return this;
  600. }
  601.  
  602. TStreamable *TMenuView::build()
  603. {
  604.     return new TMenuView( streamableInit );
  605. }
  606.  
  607. TMenuView::TMenuView( StreamableInit ) : TView( streamableInit )
  608. {
  609. }
  610.  
  611.  
  612. #endif
  613.