EnglishРусский  

   ..

   addustr.g

   app.g

   btn.g

   btnpic.g

   comp.g

   ctrl.g

   ctrlci.g

   dialogs.g

   dlgbtns.g

   edit.g

   events.g

   fonts.g

   form.g

   gray.g

   grey.g

   header.g

   images.g

   label.g

   labeled.g

   locustr.g

   menu.g

   panel.g

   picture.g

   styles.g

   tab.g

   tabitem.g

   tabpage.g

   timer.g

   toolbar.g

   tray.g

   treeview.g

   url.g

   vis.g

   viswin.g

The project is closed! You can look at a new scripting language. It is available on GitHub.
Also, try our open source cross-platform automation software.

Ads

Installer and installation software
Commercial and Freeware installers.

source\lib\vis\treeview.g
   1 /******************************************************************************
   2 *
   3 * Copyright (C) 2004-2007, The Gentee Group. All rights reserved. 
   4 * This file is part of the Gentee open source project - http://www.gentee.com. 
   5 * 
   6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT"). 
   7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS 
   8 * ACCEPTANCE OF THE AGREEMENT.
   9 *
  10 * ID: vis.treeview 25.09.07 0.0.A.
  11 *
  12 * Author: Alexander Krivonogov ( gentee )
  13 *
  14 ******************************************************************************/
  15 include {   
  16  //  "app.g"
  17    "..\\gt\\gt.g"
  18 }
  19 
  20 define <export>{
  21    TVSORT_NONE          = 0
  22    TVSORT_SORT          = 1
  23    TVSORT_RECURSE       = 2   
  24    TVSORT_NONERECURSE   = $TVSORT_NONE | $TVSORT_RECURSE   
  25    TVSORT_SORTRECURSE   = $TVSORT_SORT | $TVSORT_RECURSE
  26 }
  27 
  28 
  29 
  30 type TVItem <index=this inherit=gtitem>
  31 {
  32    
  33 }
  34 
  35 type TVSelection <index=TVItem>
  36 {  
  37    uint pTreeView
  38    arr  Items of uint
  39    uint StartShift
  40 }
  41 
  42 type treedata
  43 {
  44    //uint TreeView
  45    uint treeview //Объект содержащий данный элемент
  46    uint handle //Идентификатор элемента в окне
  47    //uint inselection
  48    
  49    //uint tag
  50    //uint gttree   
  51 }
  52 
  53 type evparTVEdit <inherit=evparEvent> 
  54 {   
  55    uint Item
  56    ustr NewLabel   
  57    uint flgCancel
  58 }
  59 
  60 type evTVEdit <inherit=evEvent> :
  61 
  62 method evTVEdit evTVEdit.init
  63 {
  64    this.eventtypeid = evparTVEdit
  65    return this
  66 }
  67 
  68 /*
  69 
  70 type evparItemMoved <inherit=evparEvent>
  71 {
  72    uint SrcItem
  73    uint DestItem
  74    uint Flag
  75 }
  76 
  77 type evItemMoved <inherit=evEvent> : 
  78 
  79 method evItemMoved evItemMoved.init
  80 {
  81    this.eventtypeid = evparItemMoved
  82    return this
  83 }
  84 */
  85 /* Компонента vTreeView, порождена от vCtrl
  86 События
  87    onClick - вызывается при нажатии на кнопку
  88 */
  89 type vTreeView <inherit = vCtrl>
  90 {
  91 //Hidden Fields
  92    uint    fConnectGt
  93    /*locustr pCaption     
  94    uint    pChecked 
  95    uint    ptreeviewStyle*/
  96    uint    pShowPlusMinus  //Показывать +/-
  97    uint    pShowLines      //Показывать линейки дерева
  98    uint    pShowRootLines  //Показывать корневую линейку
  99    uint    pShowSelection  //Всегда показывать выделение
 100    uint    pRowSelect      //Выделение элемента в виде строки
 101    uint    pLabelEdit      //Возможность редактирования элементов
 102    uint    pBorder         //Показывать рамку
 103    uint    pSorted         //Сортировать элементы
 104    uint    pSelected       //Текущий выбранный элемент
 105    uint    pMultiSelect    //Выделение нескольких элементов
 106    uint    pAutoDrag       //Возможность перетаскивать элементы
 107 //   uint    pDragDrop
 108    uint    fDrag           //Флаг, находимся в режиме drag'n'drop
 109    uint    fFromMouse
 110    uint    fMoving
 111    uint    fReleasing //Находимся в режиме освобождения
 112    ustr    pImageList
 113    uint    ptrImageList
 114    ustr    pStateImageList
 115    uint    ptrStateImageList
 116    uint    iNumIml
 117    uint    iStateNumIml
 118    //arr items[1] of TVItem
 119    //arr     pSelections of uint
 120    TVSelection Selection
 121    gt      gttree          //Представление в виде gt
 122    uint    gtroot
 123 //Events   
 124    //onevent onStartEdit
 125    evTVEdit   OnAfterEdit
 126    evTVEdit   OnBeforeEdit
 127    evQuery    OnBeforeSelect
 128    evValUint  OnAfterSelect
 129    //evTVBefore OnBeforeExpand
 130    //evTVAfter  OnAfterExpand
 131    //evTVBefore OnBeforeCollapse
 132    //evTVAfter  OnAfterCollapse
 133    //evItemMoved OnItemMoved
 134    evBeforeMove OnBeforeMove
 135    evAfterMove  OnAfterMove
 136 }
 137 
 138 /*define {
 139 //Стили кнопки treeviewStyle
 140    bsClassic    = 0 
 141    bsAsRadiotreeview = 3
 142    bsAsCheckBox = 4
 143 }*/
 144 
 145 extern {
 146 //property uint TVItem.InSelections
 147 //property TVItem.InSelections( uint val )
 148 property TVItem vTreeView.Selected()
 149 property vTreeView.Selected( TVItem item )
 150 property ustr TVItem.Label<result>()
 151 property TVItem TVItem.Child()
 152 property TVItem TVItem.Prev()
 153 //method TVItem.WinSet( uint mask )
 154 property TVItem vTreeView.Root
 155 method TVItem.Del()
 156 method vTreeView.Reload()
 157 }
 158 
 159 include {
 160    "treeviewitem.g"
 161 }
 162 
 163 /*Метод vToolBar.iUpdateImageList()
 164 Обновить ImageList
 165 */
 166 method vTreeView.iUpdateImgList()
 167 {
 168    .ptrImageList = &.GetImageList( .pImageList, &.iNumIml )
 169    if .ptrImageList
 170    {
 171       .WinMsg( $TVM_SETIMAGELIST, $TVSIL_NORMAL, .ptrImageList->ImageList.arrIml[.iNumIml].hIml )
 172    }
 173    else 
 174    {
 175       .WinMsg( $TVM_SETIMAGELIST, $TVSIL_NORMAL, 0 )
 176    }
 177    .ptrStateImageList = &.GetImageList( .pStateImageList, &.iStateNumIml )
 178    if .ptrStateImageList
 179    {
 180       .WinMsg( $TVM_SETIMAGELIST, $TVSIL_STATE, .ptrStateImageList->ImageList.arrIml[.iNumIml].hIml )
 181    }
 182    else 
 183    {
 184       .WinMsg( $TVM_SETIMAGELIST, $TVSIL_STATE, 0 )
 185    }
 186    .Invalidate()
 187 }
 188 /*------------------------------------------------------------------------------
 189    Public Methods
 190 */
 191 
 192 method vTreeView.iWinClear( uint flgdelitem )
 193 {
 194    .Selection.Clear()
 195    .Selected = 0->TVItem
 196       
 197    //.pSelected = 0
 198    .fReleasing = 1
 199    .WinMsg( $TVM_DELETEITEM, 0, 0 )
 200 //   .Root.iWinClear( flgdelitem )
 201    uint children as .Root.Children
 202    if &children
 203    {      
 204       uint prev as children.lastchild()->TVItem      
 205       while &prev
 206       {       
 207          prev.iWinClear( flgdelitem )
 208          uint cur as prev
 209          prev as cur.Prev
 210          if flgdelitem :  cur.del()
 211       }
 212    }   
 213    .fReleasing = 0
 214 }
 215 
 216 method vTreeView.Clear()
 217 {   
 218    .iWinClear( 1 )
 219 /*   .fReleasing = 1
 220    .WinMsg( $TVM_DELETEITEM, 0, 0 )
 221    .Root.iWinClear( 1 )
 222    .fReleasing = 0*/
 223    /*.Root.Release()
 224    .gttree.clear()
 225    .Reload()*/
 226    //.Root.Del()
 227    //.WinMsg( $TVM_DELETEITEM, 0, $TVI_ROOT )
 228    //.gttree.clear()
 229    /*if *.items > 1
 230    {
 231       .items.del( 1, *.items - 2 )
 232       .WinMsg( $TVM_DELETEITEM, 0, $TVI_ROOT )
 233       .gti.clear()
 234    }   */
 235 }
 236 
 237 method vTreeView.Edit()
 238 {
 239    if &(.Selected())
 240    {
 241       .SetFocus()      
 242       .WinMsg( $TVM_EDITLABELW, 0, .Selected().param->treedata.handle )      
 243    }
 244 }
 245 
 246 
 247 method vTreeView.ReloadGTItem( TVItem parent, TVItem item )
 248 {
 249    //if &parent
 250    {        
 251    
 252       uint itemdata as new( treedata )->treedata
 253       itemdata.treeview = &this
 254       item.param = &itemdata
 255       /*child.set( "name", name.toutf8( "" ) )
 256       child.setuint( "tag", tag )*/      
 257       //TVINSERTSTRUCT ti
 258       //ti.item.pszText = name.ptr()
 259       /*uint sorttype = .getuint( "sorttype" )       
 260       if sorttype & $TVSORT_SORT
 261       {         
 262          //ti.hInsertAfter = $TVI_SORT
 263          if sorttype == $TVSORT_SORTRECURSE 
 264          {
 265             child.setuint( "sorttype", sorttype )
 266          }         
 267       }*/
 268       if &parent :  parent.iItemInsert( item )
 269    }
 270    uint children as item.Children
 271    if &children
 272    {      
 273       foreach child, children
 274       {
 275          .ReloadGTItem( item, child->TVItem )
 276       }
 277    }
 278    item.iItemUpdate( $TVIF_STATE | $TVIF_TEXT | $TVIF_SELECTEDIMAGE | $TVIF_IMAGE)
 279 }
 280 
 281 method vTreeView.Reload()
 282 {   
 283 
 284    uint index
 285    if !.gtroot 
 286    {
 287       .gtroot = &this.gttree.root()
 288    }
 289    else
 290    {
 291       //this.Root.Release()  
 292           
 293       .iWinClear( 0 )
 294       
 295       
 296    }
 297 
 298    .pSelected = 0
 299    uint root as this.Root
 300    //root.Release()    
 301    uint children as root.Children   
 302    if !&children 
 303    {      
 304       children as root.insertchild( "children", 0->gtitem )      
 305       //foreach child, root->gtitem
 306       uint child as root->gtitem.child()
 307       while &child       
 308       {         
 309          uint next as child.getnext() 
 310          if &child != &children
 311          {            
 312             child.move( children, $TREE_LAST )
 313             child.gettreeitem().changenode( children.gettreeitem() )
 314          } 
 315          child as next
 316       }
 317       /*.gttree.write( "tmp.gt" )
 318       .gttree.clear()
 319       .gttree.read( "tmp.gt" )*/
 320    }   
 321    this.ReloadGTItem( 0->TVItem, root )
 322    uint child as root.Child
 323    
 324    //.Selected = 0->TVItem
 325    if &child
 326    {   
 327       .Selected = child
 328    }     
 329    
 330    this.Root().SortType = ?( .pSorted, $TVSORT_SORTRECURSE, $TVSORT_NONE )
 331 }
 332 
 333 
 334 method vTreeView.ConnectGt( gtitem gtroot )
 335 {
 336  /*  int i
 337    for i = *.Rows - 1, i >= 0, i-- 
 338    {
 339       .Rows[i].Release()
 340    }
 341    */
 342    
 343    .iWinClear( 0 )
 344    //.Root.Release()
 345    
 346    if !.fConnectGt
 347    {
 348       //.gtroot->gtitem.del()
 349       .gtroot = 0
 350    }
 351    /*else
 352    {
 353       
 354    }*/
 355    
 356    /**/   
 357    if >root 
 358    {
 359       .gtroot = >root
 360       .fConnectGt = 1
 361    }
 362    else
 363    {
 364       .gtroot = 0
 365       .fConnectGt = 0  
 366    }   
 367    .Reload()  
 368     
 369 }
 370 
 371 method vTreeView.DisconnectGt( )
 372 {
 373    
 374    if .fConnectGt : .ConnectGt( 0->gtitem)
 375    //.gtrows = 0
 376 }
 377 
 378 method TVItem vTreeView.HitTest( uint x y uint pflags )
 379 {
 380    uint item
 381    
 382    TVHITTESTINFO tvht             
 383    tvht.pt.x = x
 384    tvht.pt.y = y
 385    
 386    uint dest = .WinMsg( $TVM_HITTEST, 0, &tvht )
 387    if pflags : pflags->uint = tvht.flags 
 388    if dest
 389    {
 390       TVITEM tvi
 391       tvi.mask = $TVIF_PARAM
 392       tvi.hItem = dest
 393       .WinMsg( $TVM_GETITEMW, 0, &tvi )
 394       item = tvi.lParam
 395    }
 396    return item->TVItem
 397 }
 398 
 399 
 400 method vTreeView.DelSelected()
 401 {
 402    int i
 403    .Selection.RemoveChildren()
 404    for i = *.Selection-1, i >= 0, i--
 405    {
 406       .Selection[i].Del()
 407    }
 408 }
 409 
 410 method vTreeView.ExpandAll( uint val )
 411 {  
 412    .Root.ExpandRecurse( val ) 
 413 }
 414 /*------------------------------------------------------------------------------
 415    Properties
 416 */
 417 /*Свойство ustr Border - Get Set
 418 Установить, получить наличие рамки у поля ввода
 419 1 - рамка есть
 420 0 - рамки нет
 421 */
 422 property vTreeView.Border( uint val )
 423 {
 424    .pBorder = val
 425    uint style = GetWindowLong( this.hwnd, $GWL_EXSTYLE )
 426    if val : style |= $WS_EX_CLIENTEDGE
 427    else : style &= ~$WS_EX_CLIENTEDGE
 428    SetWindowLong( this.hwnd, $GWL_EXSTYLE, style )      
 429    SetWindowPos( this.hwnd, 0, 0, 0, 0, 0, $SWP_FRAMECHANGED | 
 430                   $SWP_NOACTIVATE | $SWP_NOZORDER | $SWP_NOMOVE | $SWP_NOSIZE )
 431 }
 432 
 433 property uint vTreeView.Border
 434 {   
 435    //.pBorder = ?(GetWindowLong( this.hwnd, $GWL_EXSTYLE ) & $WS_EX_CLIENTEDGE,1,0)
 436    return .pBorder
 437 }
 438 
 439 /*Свойство ustr ShowPlusMinus - Get Set
 440 Установить, получить отображение кнопочки с крестиком/минусом отображающим 
 441 открытие ветки
 442 1 - кнопка есть
 443 0 - кнопок нет
 444 */
 445 property vTreeView.ShowPlusMinus( uint val )
 446 {   
 447    .pShowPlusMinus = val
 448    .SetStyle( $TVS_HASBUTTONS, val )
 449 }
 450 
 451 property uint vTreeView.ShowPlusMinus
 452 { 
 453    return .pShowPlusMinus//.GetStyle( $TVS_HASBUTTONS )
 454 }
 455 
 456 /*Свойство ustr ShowLines - Get Set
 457 Установить, получить отображение линеек слева от веток
 458 1 - есть
 459 0 - нет
 460 */
 461 property vTreeView.ShowLines( uint val )
 462 {   
 463    .pShowLines = val
 464    .SetStyle( $TVS_HASLINES , val )
 465 }
 466 
 467 property uint vTreeView.ShowLines
 468 { 
 469    return .pShowLines//.GetStyle( $TVS_HASLINES )
 470 }
 471 
 472 /*Свойство ustr ShowRootLines - Get Set
 473 Установить, получить отображение линеек у корневого элемента
 474 открытие ветки
 475 1 - есть
 476 0 - нет
 477 */
 478 property vTreeView.ShowRootLines( uint val )
 479 {   
 480    .pShowRootLines = val
 481    .SetStyle( $TVS_LINESATROOT, val )
 482 }
 483 
 484 property uint vTreeView.ShowRootLines
 485 { 
 486    return .pShowRootLines//.GetStyle( $TVS_LINESATROOT )
 487 }
 488 
 489 /*Свойство ustr ShowSelection - Get Set
 490 Установить, получить отображение линеек слева от веток
 491 1 - есть
 492 0 - нет
 493 */
 494 property vTreeView.ShowSelection( uint val )
 495 {   
 496    .pShowSelection = val
 497    .SetStyle( $TVS_SHOWSELALWAYS, val )
 498 }
 499 
 500 property uint vTreeView.ShowSelection
 501 { 
 502    return .pShowSelection//.GetStyle( $TVS_HASLINES )
 503 }
 504 
 505 /*Свойство ustr RowSelect - Get Set
 506 Установить, получить отображение линеек слева от веток
 507 1 - есть
 508 0 - нет
 509 */
 510 property vTreeView.RowSelect( uint val )
 511 {   
 512    .pRowSelect = val
 513    .SetStyle( $TVS_FULLROWSELECT , val )
 514 }
 515 
 516 property uint vTreeView.RowSelect
 517 { 
 518    return .pRowSelect//.GetStyle( $TVS_HASLINES )
 519 }
 520 
 521 /*Свойство ustr LabelEdit - Get Set
 522 Установить, получить отображение линеек слева от веток
 523 1 - есть
 524 0 - нет
 525 */
 526 property vTreeView.LabelEdit( uint val )
 527 {   
 528    .pLabelEdit = val
 529    .SetStyle( $TVS_EDITLABELS , val )
 530 }
 531 
 532 property uint vTreeView.LabelEdit
 533 { 
 534    return .pLabelEdit//.GetStyle( $TVS_HASLINES )
 535 }
 536 
 537 /* Свойство str vTreeView.ImageList - Get Set
 538 Устанавливает или получает имя списка картинок
 539 */
 540 property ustr vTreeView.ImageList <result>
 541 {
 542    result = this.pImageList
 543 }
 544 
 545 property vTreeView.ImageList( ustr val )
 546 {
 547    if val != this.pImageList
 548    { 
 549       this.pImageList = val
 550       .Virtual( $mLangChanged )      
 551       //.iUpdateImageList()
 552    }
 553 }
 554 
 555 /* Свойство str vTreeView.StateImgListName - Get Set
 556 Устанавливает или получает имя списка картинок состояний
 557 */
 558 property ustr vTreeView.StateImageList <result>
 559 {
 560    result = this.pStateImageList
 561 }
 562 
 563 property vTreeView.StateImageList( ustr val )
 564 {
 565    if val != this.pStateImageList
 566    { 
 567       this.pStateImageList = val
 568       .Virtual( $mLangChanged )
 569       //.iUpdateImageList()
 570    }
 571 }
 572 
 573 /* Свойство uint vTreeView.MultiSelect - Get Set
 574 Выделение нескольких элементов
 575 */
 576 property uint vTreeView.MultiSelect()
 577 {
 578    return .pMultiSelect
 579 }
 580 
 581 property vTreeView.MultiSelect( uint val )
 582 {
 583    if val != this.pMultiSelect
 584    { 
 585       this.pMultiSelect = val      
 586    }
 587 }
 588 
 589 
 590 /* Свойство uint vListView.AutoDrag - Get Set
 591 Возможность перетаскивать элементы внутри объекта
 592 */
 593 property uint vTreeView.AutoDrag()
 594 {
 595    return .pAutoDrag
 596 }
 597 
 598 property vTreeView.AutoDrag( uint val )
 599 {
 600    this.pAutoDrag = val   
 601 }
 602 
 603 /*property  TVSelections vTreeView.Selections
 604 {
 605    return this->TVSelections
 606 }
 607 
 608 
 609 
 610 method TVItem TVSelections.index( uint idx )
 611 {
 612    uint tv as this->vTreeView
 613    if idx < *tv.pSelections 
 614    {
 615       return tv.pSelections[idx]->TVItem
 616    }
 617    return 0->TVItem 
 618 }
 619 
 620 operator uint * ( TVSelections sel )
 621 {
 622    return *sel->vTreeView.pSelections
 623 }
 624 
 625 method TVSelections.Clear()
 626 {
 627    uint tv as this->vTreeView
 628    while *tv.pSelections 
 629    {
 630       tv.pSelections[0]->TVItem.InSelections = 0
 631    }  
 632 }*/
 633 /*method TVItem.Index( uint 0 )
 634 {
 635    
 636 }*/
 637 
 638 
 639 property TVItem vTreeView.Root
 640 {
 641    if &this
 642    {
 643       return .gtroot->TVItem//.gttree.root()->TVItem//.items[0]
 644    }
 645    return 0->TVItem
 646 }
 647 
 648 
 649 
 650 /* Свойство uint Sorted - Get Set
 651 Устанавливает или определяет должны ли сортироваться элементы в дереве
 652 1 - элементы сортируются
 653 0 - элементы не сортируются
 654 */
 655 property uint vTreeView.Sorted()
 656 {  
 657    return this.pSorted
 658 }
 659 
 660 property vTreeView.Sorted( uint val)
 661 {
 662    if this.pSorted != val
 663    {
 664       this.pSorted = val
 665       this.Root().SortType = ?( val, $TVSORT_SORTRECURSE, $TVSORT_NONE )
 666       
 667    }
 668 }
 669 
 670 property TVItem vTreeView.Selected()
 671 {     
 672    return this.pSelected->TVItem
 673 }
 674 
 675 property vTreeView.Selected( TVItem item )
 676 {   
 677    if this.pSelected != &item
 678    {
 679       uint destitem = &item
 680       if destitem == &this.Root : destitem = 0
 681       //this.pSelected = destitem
 682       .WinMsg( $TVM_SELECTITEM, $TVGN_CARET, ?( destitem, destitem->TVItem.param->treedata.handle, 0) )      
 683    }
 684 }
 685 
 686 /* Свойство uint InSelections - Get Set
 687 Устанавливает или определяет находится ли элемент в числе выбранных
 688 */
 689 /*property uint TVItem.InSelections
 690 { 
 691    return .param->treedata.inselections 
 692 }
 693 
 694 property TVItem.InSelections( uint val )
 695 {
 696    if val != .param->treedata.inselections
 697    { 
 698       .param->treedata.inselections = val
 699       uint sels as .param->treedata.treeview->vTreeView.pSelections
 700       if val
 701       {
 702          sels[sels.expand( 1 )] = &this
 703       }
 704       else
 705       {
 706          uint i
 707          fornum i = 0, *sels
 708          {
 709             if sels[i] == &this
 710             {
 711                sels.del(i)
 712                break;
 713             }
 714          }
 715       }
 716       .iItemUpdate( $TVIF_STATE )
 717    }
 718 }
 719 */
 720 
 721 /* Свойство uint treeviewStyle - Get Set
 722 Усотанавливает или определяет стиль кнопки
 723 Возможны следующие варианты:
 724 bsClassic     - обычный вид,
 725 bsAsRadiotreeview  - работает как Radiotreeview,
 726 bsAsCheckBox  - работает как CheckBox
 727 */
 728 /*property uint vTreeView.treeviewStyle()
 729 {
 730    return this.ptreeviewStyle
 731 }
 732 
 733 property vTreeView.treeviewStyle( uint val)
 734 {
 735    if this.ptreeviewStyle != val
 736    {      
 737       uint checked = this.Checked
 738       uint remstyle = $BS_AUTORADIOBUTTON | $BS_AUTOCHECKBOX | $BS_PUSHLIKE
 739       uint addstyle
 740       this.WinMsg( $BM_SETCHECK, 0 )
 741       this.pChecked = 0
 742       if val == $bsAsRadiotreeview
 743       {
 744          addstyle = $BS_AUTORADIOBUTTON | $BS_PUSHLIKE
 745       }
 746       elif val == $bsAsCheckBox
 747       {
 748          addstyle = $BS_AUTOCHECKBOX | $BS_PUSHLIKE  
 749       }      
 750       this.ChangeStyle( addstyle, remstyle ) 
 751       this.ptreeviewStyle = val      
 752       this.Checked = checked
 753    }
 754 }
 755 */
 756 /* Свойство uint Caption - Get Set
 757 Усотанавливает или определяет заголовок кнопки
 758 */
 759 /*property ustr vTreeView.Caption <result>
 760 {
 761    result = this.pCaption.Value
 762 }
 763 
 764 property vTreeView.Caption( ustr val )
 765 {   
 766    this.pCaption.Value = val
 767    SetWindowText( this.hwnd, this.pCaption.Text.ptr() )    
 768 }
 769 
 770 
 771 */
 772 /*------------------------------------------------------------------------------
 773    Virtual Methods
 774 */
 775 /*Виртуальный метод vTreeView vTreeView.mCreateWin - Создание окна
 776 */
 777 method vTreeView vTreeView.mCreateWin <alias=vTreeView_mCreateWin>()
 778 {
 779    uint exstyle
 780    uint style = $WS_CHILD | $WS_CLIPSIBLINGS
 781    if .pShowPlusMinus : style |= $TVS_HASBUTTONS 
 782    if .pShowLines     : style |= $TVS_HASLINES
 783    if .pShowRootLines : style |= $TVS_LINESATROOT
 784    if .pShowSelection : style |= $TVS_SHOWSELALWAYS
 785    if .pRowSelect     : style |= $TVS_FULLROWSELECT
 786    if .pLabelEdit     : style |= $TVS_EDITLABELS
 787    
 788    if .pBorder : exstyle |= $WS_EX_CLIENTEDGE   
 789    this.CreateWin( "SysTreeView32".ustr(), exstyle, style )         
 790    this->vCtrl.mCreateWin()      
 791    this.WinMsg( $WM_SETFONT, GetStockObject( $DEFAULT_GUI_FONT ) )
 792    .iUpdateImgList()
 793    //uint himl = ImageList_Create(16, 16, 0xFE, 1, 0)
 794    //uint hbitmap = LoadBitmap( 0,  32754 )//"OBM_CHECKBOXES".ustr().ptr() )
 795    //ImageList_Add( himl,hbitmap,0)
 796    //DeleteObject( hbitmap )
 797    //hbitmap = LoadBitmap( 0, 32759 )//"OBM_CHECKBOXES".ustr().ptr() )
 798    //ImageList_Add( himl,hbitmap,0)
 799    //DeleteObject( hbitmap )
 800    //.WinMsg( $TVM_SETINDENT, -20 )
 801 //   .WinMsg( $TVM_SETIMAGELIST, 0, himl ); 
 802    .Reload()                                                                 
 803    return this
 804 }
 805 
 806 /*Виртуальный метод uint vTreeView.mWinNtf - обработка сообщений
 807 */
 808 method uint vTreeView.mWinNtf <alias=vTreeView_mWinNtf>( winmsg wmsg )//NMHDR ntf )
 809 {   
 810    uint nmtv as wmsg.lpar->NMTREEVIEWW
 811    switch nmtv.hdr.code
 812    {
 813       case $NM_RCLICK
 814       {
 815          //TVHITTESTINFO tvht
 816          POINT pt
 817          uint lpar
 818          //uint curitem
 819            
 820          GetCursorPos( pt )
 821          lpar = ( pt.y << 16 ) | pt.x
 822          ScreenToClient( .hwnd, pt )
 823          /*tvht.pt = pt
 824       	if curitem = .WinMsg( $TVM_HITTEST, 0, &tvht )
 825          {
 826       	    .WinMsg( $TVM_SELECTITEM, $TVGN_CARET, curitem )
 827          }*/
 828          
 829          .WinMsg( $WM_CONTEXTMENU, this.hwnd, lpar )
 830       }
 831       case $TVN_GETDISPINFOW
 832       {      
 833          nmtv as NMTVDISPINFO   
 834          //uint nd as ntf->NMTVDISPINFO
 835          if nmtv.item.mask & $TVIF_IMAGE
 836          {
 837             nmtv.item.iImage = -1
 838          }
 839          if nmtv.item.mask & $TVIF_SELECTEDIMAGE
 840          {
 841             nmtv.item.iSelectedImage = -1
 842          }      
 843       return 0
 844       }
 845       case $TVN_SELCHANGEDW
 846       {    
 847          uint selected = ?( nmtv.itemNew.hItem, nmtv.itemNew.lParam, 0 )
 848          if selected == this.pSelected : return 0
 849          this.pSelected = selected
 850          
 851          if .pMultiSelect
 852          { 
 853             if !.fReleasing                                    
 854             {
 855                nmtv as NMTREEVIEWW
 856                if GetKeyState( $VK_SHIFT ) & 0x8000// nmtv.action == 2/*$TVC_BYMOUSE*/ &&  
 857                {
 858                   if nmtv.itemNew.lParam
 859                   {
 860                      if .fFromMouse
 861                      {
 862                         if nmtv.itemOld.lParam
 863                         {
 864                            if .Selection.Find( nmtv.itemOld.lParam->TVItem ) != -1
 865                            {
 866                               .Selection.iSelect( nmtv.itemOld.lParam->TVItem, 1 )
 867                            } 
 868                         }
 869                      }
 870                      else 
 871                      {
 872                         .Selection.Clear()
 873                      }
 874                      uint item
 875                      uint flgselect
 876                      item as .Root
 877                      if .Selection.StartShift
 878                      {
 879                         while ( item as item.NextInList )
 880                         {          
 881                            if !flgselect 
 882                            {
 883                               if &item == .Selection.StartShift : flgselect = 1 
 884                               elif &item == nmtv.itemNew.lParam : flgselect = 2
 885                               else : continue                        
 886                            }                     
 887                            {
 888                               .Selection.Append( item )
 889                               if ( flgselect == 2 && &item == .Selection.StartShift ) ||
 890                                  ( flgselect == 1 && &item == nmtv.itemNew.lParam )
 891                               {
 892                                  break
 893                               }
 894                            }
 895                            
 896                         } 
 897                      } 
 898                      else 
 899                      {
 900                         .Selection.StartShift = nmtv.itemNew.lParam
 901                         .Selection.Append( nmtv.itemNew.lParam->TVItem )
 902                      }           
 903                   }
 904                }      
 905                elif GetKeyState( $VK_CONTROL ) & 0x8000 && .fFromMouse/*$TVC_BYMOUSE*/   
 906                {
 907                   if nmtv.itemNew.lParam
 908                   {
 909                      if .Selection.Find( nmtv.itemNew.lParam->TVItem ) != -1
 910                      {                
 911                         .Selection.Remove( nmtv.itemNew.lParam->TVItem )
 912                      }  
 913                      else 
 914                      {                
 915                         .Selection.Append( nmtv.itemNew.lParam->TVItem )
 916                      }
 917                      .Selection.StartShift = nmtv.itemNew.lParam
 918                   } 
 919                   if nmtv.itemOld.lParam
 920                   {
 921                      if .Selection.Find( nmtv.itemOld.lParam->TVItem ) != -1
 922                      {
 923                         .Selection.iSelect( nmtv.itemOld.lParam->TVItem, 1 )
 924                      } 
 925                   }            
 926                }  
 927                else
 928                {  
 929                   .Selection.Clear()  
 930                   if nmtv.itemNew.lParam 
 931                   {
 932                    /*  if .Selection.Find( nmtv.itemNew.lParam->TVItem ) == -1
 933                      {
 934                         .Selection.Clear()
 935                         .Selection.Append( nmtv.itemNew.lParam->TVItem )
 936                      }       
 937                      else
 938                      {
 939                         //InvalidateRect( this.hwnd, 0->RECT, 0 )
 940                         //.Selections.iWinUpdate( 1 )
 941                          
 942                         if nmtv.itemOld.lParam
 943                         {
 944                            if .Selection.Find( nmtv.itemOld.lParam->TVItem ) != -1
 945                            {
 946                               .Selection.iSelect( nmtv.itemOld.lParam->TVItem, 1 )
 947                            } 
 948                         }
 949                      }    */            
 950                      .Selection.Append( nmtv.itemNew.lParam->TVItem )
 951                      .Selection.StartShift = nmtv.itemNew.lParam
 952                   }               
 953                }
 954             }
 955             else
 956             {
 957                if nmtv.itemNew.lParam
 958                {
 959                   .Selection.Append( nmtv.itemNew.lParam->TVItem )       
 960                   .Selection.StartShift = nmtv.itemNew.lParam
 961                }
 962             }
 963                  
 964             //if nmtv.itemOld.lParam &&
 965             //   (( nmtv.action == 1/*$TVC_BYMOUSE*/ &&  GetKeyState( $VK_CONTROL ) & 0x8000 ) ||
 966             //    ( nmtv.action == 2/*$TVC_BYKEYBOARD*/ &&  GetKeyState( $VK_SHIFT ) & 0x8000 ))
 967             
 968             //   nmtv.itemOld.lParam->TVItem.InSelections = !nmtv.itemOld.lParam->TVItem.InSelections
 969                //wmsg.flags = 1
 970             
 971             
 972          }
 973          else
 974          {
 975             .Selection.Clear()
 976             if &this.Selected
 977             {
 978                .Selection.Append( this.Selected )
 979             } 
 980          }
 981          evparValUint etva         
 982          etva.val = this.pSelected
 983          etva.sender = &this      
 984          .OnAfterSelect.Run( /*this,*/ etva )         
 985       }
 986       case $TVN_SELCHANGINGW
 987       {      
 988          if .fMoving 
 989          {
 990             wmsg.flags = 1
 991             return 1
 992          }
 993        /*  nmtv as NMTREEVIEWW      
 994          if  nmtv.action == 1 &&  GetKeyState( $VK_CONTROL ) & 0x8000
 995          {
 996             wmsg.flags= 1
 997             return 1
 998          }*/        
 999          evparQuery etvb
1000          etvb.val = ?( nmtv.itemNew, nmtv.itemNew.lParam, 0 )
1001          etvb.sender = &this                   
1002          .OnBeforeSelect.Run( /*this,*/ etvb )
1003          return etvb.flgCancel         
1004       }
1005       case $TVN_ITEMEXPANDEDW
1006       {
1007          if nmtv.action & ( $TVE_COLLAPSE | $TVE_EXPAND )
1008          {
1009             nmtv.itemNew.lParam->TVItem.setuint( "expanded", nmtv.action & $TVE_EXPAND )           
1010             
1011          }
1012          /*foreach it, this.Root()
1013          {
1014             .Selected = it   
1015             break;
1016          }*/
1017          
1018       }
1019       case $TVN_ITEMEXPANDINGW
1020       {
1021       }
1022       case $TVN_BEGINLABELEDITW
1023       {
1024          evparTVEdit etve  
1025          etve.Item = &.Selected
1026          etve.sender = &this       
1027          .OnBeforeEdit.Run( /*this,*/ etve )
1028          return etve.flgCancel
1029       }
1030       case $TVN_ENDLABELEDITW
1031       {
1032          nmtv as NMTVDISPINFO
1033          
1034          evparTVEdit etve
1035          uint item as ?( nmtv.item.hItem, nmtv.item.lParam, 0 )->TVItem
1036          
1037          etve.Item = &item 
1038          if nmtv.item.pszText
1039          {
1040             etve.NewLabel.copy( nmtv.item.pszText )     
1041          }
1042          else
1043          {
1044             etve.flgCancel = 1
1045          }
1046          etve.sender = &this
1047          .OnAfterEdit.Run( /*this,*/ etve )
1048          if !etve.flgCancel 
1049          {  
1050             if &item
1051             {
1052                item.Label = etve.NewLabel
1053             }                    
1054             /*uint selected as .Selected
1055             if &selected
1056             {    
1057                selected.Label = etve.NewLabel            
1058                //selected.set( "label", etve.NewLabel.toutf8( "" ) )
1059             } */           
1060             return 1
1061          }         
1062       }
1063       case $TVN_BEGINDRAGW
1064       {
1065          if .pAutoDrag
1066          {
1067             .Selected = nmtv.itemNew.lParam->TVItem
1068          //RECT rect 
1069          //(&rect)->uint = nmtv.itemNew.hItem
1070          //.WinMsg( $TVM_GETITEMRECT, 1, &rect )
1071          //uint hdc = GetDC( .hwnd )
1072                            
1073             SetCapture( .hwnd ) 
1074             .fDrag = 1
1075          }      
1076       }  
1077       case $TVN_DELETEITEMW
1078       {
1079       }
1080       case $NM_CUSTOMDRAW  
1081       {
1082          uint cd as wmsg.lpar->NMTVCUSTOMDRAW
1083          uint resi = $CDRF_DODEFAULT;          
1084          switch( cd.nmcd.dwDrawStage )
1085          {
1086             case $CDDS_PREPAINT: resi |= $CDRF_NOTIFYITEMDRAW;
1087             case $CDDS_ITEMPREPAINT
1088             {
1089                uint item as cd.nmcd.lItemlParam->TVItem                  
1090                if &item && item.getuint( "disabled" ) : cd.clrText = GetSysColor(16)
1091             }
1092          }
1093          wmsg.flags = 1 
1094          return resi
1095       } 
1096    }
1097    return 0
1098 }
1099 
1100 method uint vTreeView.mMouse <alias=vTreeView_mMouse>( evparMouse em )
1101 {
1102    switch em.evmtype
1103    {
1104       case $evmMove
1105       {
1106          if .fDrag 
1107          {         
1108             POINT point
1109             uint destitem
1110             //TVHITTESTINFO tvht
1111              
1112             /*tvht.pt.x = */point.x = em.x
1113             /*tvht.pt.y =*/ point.y = em.y
1114             //if dest = .WinMsg( $TVM_HITTEST, 0, &tvht)
1115             
1116             if destitem = &.HitTest( em.x, em.y, 0 )   
1117             {                 
1118                destitem as TVItem
1119                /*TVITEM tvi
1120                tvi.mask = $TVIF_PARAM
1121                tvi.hItem = dest
1122                .WinMsg( $TVM_GETITEMW, 0, &tvi )            
1123                uint destitem as tvi.lParam->TVItem*/
1124                
1125                if .Selection.Find( destitem ) == -1
1126                { 
1127                   .WinMsg( $TVM_SELECTITEM, $TVGN_DROPHILITE, destitem.param->treedata.handle )               
1128                //.WinMsg( $TVM_EXPAND, $TVE_EXPAND, destitem )
1129                   SetCursor( App.cursorDrag )
1130                }
1131                else 
1132                {
1133                   .WinMsg( $TVM_SELECTITEM, $TVGN_DROPHILITE, 0 )
1134                   SetCursor( App.cursorNoDrag )
1135                } 
1136             }
1137             else
1138             {
1139                if int( em.x ) > 0 && int( em.y ) > 0 && em.x < .clloc.width && em.y < .clloc.height
1140                {
1141                   SetCursor( App.cursorDrag )
1142                }
1143                else
1144                {
1145                   SetCursor( App.cursorNoDrag )
1146                }
1147             }
1148             ClientToScreen( .hwnd, point )
1149             //ImageList_DragMove( point.x, point.y )   
1150          }
1151       }
1152       case $evmLUp
1153       {
1154          uint dest
1155          TVHITTESTINFO tvht
1156          if .fDrag
1157          {
1158             uint destitem //as TVItem
1159             uint selected as .pSelected->TVItem
1160             uint flg
1161             
1162             //tvht.pt.x = em.x
1163             //tvht.pt.y = em.y            
1164             //if dest = .WinMsg( $TVM_HITTEST, 0, &tvht)
1165             if destitem = &.HitTest( em.x, em.y, 0 )  
1166             {
1167              /*  TVITEM item
1168                item.mask = $TVIF_PARAM
1169                item.hItem = dest
1170                .WinMsg( $TVM_GETITEMW, 0, &item )
1171             
1172                destitem as item.lParam->TVItem*/
1173                destitem as TVItem
1174                uint previtem as destitem.getprev()->TVItem
1175                if .Selection.Find( destitem ) == -1 &&
1176                   ( !&previtem || .Selection.Find( previtem ) == -1 )
1177                {                  
1178                   uint owneritem as destitem
1179                   uint root as .Root                   
1180                   do
1181                   {
1182                      if &owneritem == .pSelected
1183                      {
1184                         destitem as 0
1185                         break
1186                      }
1187                      owneritem as owneritem.Parent                     
1188                   }
1189                   while &owneritem != &root
1190                   flg = $TREE_BEFORE                  
1191                }     
1192                else : goto end          
1193             }
1194             elif int( em.x ) > 0 && int( em.y ) > 0 && em.x < .clloc.width && em.y < .clloc.height
1195             {
1196                destitem as .Root
1197                flg = $TREE_LAST
1198                //selected.MoveTo( .Root, $TREE_LAST )
1199             }  
1200             .Selection.MoveTo( destitem->TVItem, flg )                                    
1201             //ImageList_EndDrag( )
1202 label end                        
1203             ReleaseCapture()
1204             //.Selected = 0->TVItem
1205             //.Selected = selected  
1206             //.fDrag = 0
1207          }
1208       }
1209    }
1210 
1211    return this->vCtrl.mMouse( em )   
1212 }
1213 
1214 method uint vTreeView.wmcapturechange <alias=vTreeView_wmcapturechanged>( winmsg wmsg )
1215 {   
1216    if wmsg.lpar != .hwnd && .fDrag 
1217    {
1218       SetCursor( App.cursorArrow )
1219       .WinMsg( $TVM_SELECTITEM, $TVGN_DROPHILITE, 0 )
1220       .fDrag = 0
1221    } 
1222    return 0
1223 }
1224 
1225 method vTreeView.mPreDel <alias=vTreeView_mPreDel>()
1226 {
1227    .DisconnectGt()
1228    .WinMsg( $TVM_SELECTITEM, $TVGN_CARET, 0 ) 
1229    //this.Root.Del()
1230    this.Clear()
1231    //destroy( this.Root.param )
1232    this->vCtrl.mPreDel()
1233 }
1234 /*Виртуальный метод uint vTreeView.mLangChanged - Изменение текущего языка
1235 */
1236 method uint vTreeView.mLangChanged <alias=vTreeView_mLangChanged>()
1237 {
1238    .iUpdateImgList()
1239    .Root.Update()
1240    this->vCtrl.mLangChanged()
1241 //   .Caption = .Caption
1242    return 0  
1243 }
1244 
1245 method vTreeView.mFocus <alias=vTreeView_mFocus>( evparValUint ev )
1246 {
1247    if *.Selection > 1 
1248    {  
1249       .Invalidate()
1250    }
1251    this->vCtrl.mFocus( ev )   
1252 }
1253 
1254 
1255 method uint vTreeView.wmMouse <alias=vTreeView_wmMouse>( winmsg wmsg )
1256 {  
1257    //if .pShowSelection
1258    {
1259    
1260       TVHITTESTINFO tvht
1261       //POINT pt
1262       //uint lpar
1263       uint curitem
1264          
1265       //GetCursorPos( pt )
1266       //lpar = ( pt.y << 16 ) | pt.x
1267       //ScreenToClient( .hwnd, pt )
1268       tvht.pt.x = int( ( &wmsg.lpar )->short )
1269       tvht.pt.y = int( ( &wmsg.lpar + 2 )->short )
1270       if curitem = .WinMsg( $TVM_HITTEST, 0, &tvht )
1271       {         
1272          if !( tvht.flags & $TVHT_ONITEMBUTTON )
1273          {
1274             .fFromMouse = 1
1275          	.WinMsg( $TVM_SELECTITEM, $TVGN_CARET, curitem )
1276             .fFromMouse = 0         
1277          }   
1278       }
1279       //SetFocus( this.hwnd )
1280      /* LVHITTESTINFO info
1281       info.pt.x = int( ( &wmsg.lpar )->short )
1282       info.pt.y = int( ( &wmsg.lpar + 2 )->short )
1283       if .WinMsg( $LVM_HITTEST, 0, &info ) == -1*/
1284       { 
1285          //( &wmsg.lpar )->short = 5
1286          //( &wmsg.lpar + 2 )->short = 5
1287         // wmsg.flags = 1
1288          /*         
1289          info.pt.x = 5         
1290          if .WinMsg( $LVM_HITTEST, 0, &info ) != -1
1291          {              
1292             LVITEM lvi
1293             lvi.mask = $LVIF_STATE
1294             //lvi.iItem = info.iItem
1295             lvi.stateMask = $LVIS_FOCUSED | $LVIS_SELECTED 
1296             lvi.state = $LVIS_FOCUSED | $LVIS_SELECTED 
1297             .WinMsg( $LVM_SETITEMSTATE, info.iItem, &lvi )
1298          }*/
1299       }
1300    }
1301    return this->vCtrl.wmMouse( wmsg )
1302 }
1303 
1304 /*Виртуальный метод vTreeView.mSetName - Установка заголовка в режиме проектирования
1305 */
1306 /*method uint vTreeView.mSetName <alias=vTreeView_mSetName>( str newname )
1307 {
1308 ifdef $DESIGNING {   
1309    if !*.Caption || .Caption == .Name
1310    {
1311       .Caption = newname.ustr()
1312    }
1313 }   
1314    return 1
1315 }
1316 
1317 */
1318 /*------------------------------------------------------------------------------
1319    Registration
1320 */
1321 /*Системный метод vTreeView vTreeView.init - Инициализация объекта
1322 */   
1323 method vTreeView vTreeView.init( )
1324 {   
1325    this.pTypeId = vTreeView
1326      
1327    this.pCanFocus = 1
1328    this.pTabStop = 1      
1329    this.loc.width = 100
1330    this.loc.height = 25
1331    this.pBorder = 1
1332    this.pShowPlusMinus = 1
1333    this.pShowLines = 1
1334    this.pShowRootLines = 1
1335    //uint itemdata as new( treedata )->treedata
1336    //itemdata.treeview = &this
1337    //this.gttree.root().param = &itemdata
1338    
1339    .Selection.pTreeView = &this
1340    .Reload()
1341    //this.items[0].TreeView = &this
1342    //this.items[0].gti = &this.gti.root()
1343    return this 
1344 }  
1345 
1346 /*ifdef $DESIGNING
1347 {
1348 method vTreeView.mRegProps <alias=vTreeView_mRegProps>( uint typeid, compMan cm )
1349 {
1350 //   this->vCtrl.mRegProps( typeid, cm)
1351 }*/
1352 /*
1353 method vTreeView.getevents( uint typeid, compMan cm )
1354 {
1355    this->vCtrl.getevents( typeid, cm)
1356    cm.addevents( typeid, %{
1357 "onclick"      , "eventn"
1358    })
1359 }*/
1360 
1361 func init_vTreeView <entry>()
1362 {  
1363    regcomp( vTreeView, "vTreeView", vCtrl, $vCtrl_last, 
1364       %{ %{$mCreateWin,    vTreeView_mCreateWin},
1365           %{$mWinNtf,       vTreeView_mWinNtf },
1366           %{$mMouse,       vTreeView_mMouse },
1367           %{$mPreDel,      vTreeView_mPreDel },
1368          %{$mLangChanged,  vTreeView_mLangChanged },
1369           %{$mFocus,       vTreeView_mFocus }/*,
1370          %{$mSetName,      vTreeView_mSetName}*/
1371       },       
1372       %{ %{ $WM_CAPTURECHANGED, vTreeView_wmcapturechanged },
1373          %{ $WM_LBUTTONDOWN, vTreeView_wmMouse },
1374          %{ $WM_RBUTTONDOWN, vTreeView_wmMouse } 
1375       }
1376        )
1377       
1378 ifdef $DESIGNING {
1379    cm.AddComp( vTreeView, 1, "Windows", "treeview" )
1380    cm.AddProps( vTreeView, %{    
1381 //"TabOrder", uint, 0,
1382 "Border", uint, 0,
1383 "ShowPlusMinus", uint, 0,
1384 "ShowLines", uint, 0,    
1385 "ShowRootLines", uint, 0,
1386 "ShowSelection", uint, 0,
1387 "RowSelect", uint, 0,
1388 "LabelEdit", uint, 0,
1389 "ImageList", ustr, 0,
1390 "StateImageList", ustr, 0,
1391 "AutoDrag", uint, 0,
1392 "MultiSelect", uint, 0 
1393 /*"Caption",  ustr, 0,
1394 "treeviewStyle", uint, 0,
1395 "Checked",  uint, 0*/
1396    }) 
1397    /*                
1398    cm.AddPropVals( vTreeView, "treeviewStyle", %{ 
1399 "bsClassic",      $bsClassic,
1400 "bsAsRadiotreeview",   $bsAsRadiotreeview,     
1401 "bsAsCheckBox",   $bsAsCheckBox
1402    })   
1403    */
1404    cm.AddEvents( vTreeView, %{
1405 //"OnBeforeEdit", "eventTVEdit",
1406 "OnAfterEdit", "evparTVEdit",
1407 //"OnBeforeSelect", "",
1408 "OnAfterSelect", "evValUint",
1409 /*,
1410 "OnBeforeExpand", "",
1411 "OnAfterExpand", "",
1412 "OnBeforeCollapse", "",
1413 "OnAfterCollapse", ""*/
1414 "OnBeforeMove", "evparBeforeMove",
1415 "OnAfterMove", "evparAfterMove"
1416 
1417    })
1418 }
1419       
1420 }
1421