1 /* 2 Copyright (c) by Valery Goryachev (Wal) 3 */ 4 5 #include <string> 6 #include <unordered_map> 7 8 #include "string-util.h" 9 #include "swl.h" 10 #include "swl_wincore_internal.h" 11 12 namespace wal 13 { 14 15 struct WINHASHNODE 16 { 17 WinID id; 18 Win* win; 19 WINHASHNODEwal::WINHASHNODE20 WINHASHNODE( WinID h, Win* w ): id( h ), win( w ) {} WINHASHNODEwal::WINHASHNODE21 WINHASHNODE(): id( 0 ), win ( nullptr ) {} 22 keywal::WINHASHNODE23 const WinID& key() const { return id; }; 24 }; 25 26 static std::unordered_map<WinID, WINHASHNODE> winhash; 27 WinID Win::focusWinId = 0; 28 29 GetWinByID(WinID hWnd)30 Win* GetWinByID( WinID hWnd ) 31 { 32 WinID id( hWnd ); 33 auto i = winhash.find(hWnd); 34 const WINHASHNODE* node = ( i == winhash.end() ) ? nullptr : &(i->second); 35 return node ? node->win : 0; 36 } 37 DelWinFromHash(WinID w)38 int DelWinFromHash( WinID w ) 39 { 40 winhash.erase(w); 41 return winhash.size(); 42 } 43 AddWinToHash(WinID handle,Win * w)44 void AddWinToHash( WinID handle, Win* w ) 45 { 46 WINHASHNODE node( handle, w ); 47 winhash[handle] = node; 48 } 49 50 ForeachBlock(const WINHASHNODE * t,void * data)51 static void ForeachBlock( const WINHASHNODE* t, void* data ) { t->win->Block( *( ( WinID* )data ) );} ForeachUnblock(const WINHASHNODE * t,void * data)52 static void ForeachUnblock( const WINHASHNODE* t, void* data ) { t->win->Unblock( *( ( WinID* )data ) );} AppBlock(WinID w)53 void AppBlock( WinID w ) { for ( const auto& i : winhash ) ForeachBlock( &(i.second), &w ); } AppUnblock(WinID w)54 void AppUnblock( WinID w ) { for ( const auto& i : winhash ) ForeachUnblock( &(i.second), &w ); } 55 56 57 struct TimerStruct 58 { 59 WinID winId; 60 int timerId; 61 unsigned period; 62 unsigned last; 63 }; 64 65 static ccollect<TimerStruct> timerList; 66 unsigned GetTickMiliseconds(); 67 __TimerAppend(WinID wid,int tid,unsigned period)68 static void __TimerAppend( WinID wid, int tid, unsigned period ) 69 { 70 if ( !period ) { period = 0; } 71 72 TimerStruct ts; 73 ts.winId = wid; 74 ts.timerId = tid; 75 ts.period = period; 76 ts.last = GetTickMiliseconds(); 77 timerList.append( ts ); 78 } 79 TimerDel(WinID wid,int tid)80 static void TimerDel( WinID wid, int tid ) 81 { 82 for ( int i = 0, n = timerList.count(); i < n; ) 83 { 84 TimerStruct* ts = timerList.ptr() + i; 85 86 if ( ts->winId == wid && ts->timerId == tid ) 87 { 88 timerList.del( i ); 89 n--; 90 } 91 else { i++; } 92 } 93 } 94 TimerReset(WinID wid,int tid,unsigned period)95 static void TimerReset( WinID wid, int tid, unsigned period ) 96 { 97 if ( !period ) { period = 0; } 98 99 for ( int i = 0, n = timerList.count(); i < n; i++ ) 100 { 101 TimerStruct* ts = timerList.ptr() + i; 102 103 if ( ts->winId == wid && ts->timerId == tid ) 104 { 105 timerList[i].period = period; 106 return; 107 } 108 } 109 110 __TimerAppend( wid, tid, period ); 111 } 112 TimerDel(WinID wid)113 void TimerDel( WinID wid ) 114 { 115 for ( int i = 0; i < timerList.count(); ) 116 { 117 if ( timerList[i].winId == wid ) 118 { 119 timerList.del( i ); 120 } 121 else 122 { 123 i++; 124 } 125 } 126 } 127 128 struct RunTimersNode 129 { 130 WinID wid; 131 int tid; 132 }; 133 134 RunTimers()135 unsigned RunTimers() 136 { 137 138 ccollect<RunTimersNode> runList; 139 unsigned tim = GetTickMiliseconds(); 140 int i, n; 141 142 //printf("count timers %i\n", timerList.count()); 143 for ( i = 0, n = timerList.count(); i < n; i++ ) 144 { 145 TimerStruct* ts = timerList.ptr() + i; 146 147 //printf("tim%i (%i,%i)\n",1, tim, ts->last); 148 149 if ( tim - ts->last >= ts->period ) //! условие должно соответствовать условию * 150 { 151 ts->last = tim; 152 RunTimersNode node; 153 node.wid = ts->winId; 154 node.tid = ts->timerId; 155 runList.append( node ); 156 } 157 } 158 159 //printf("running timers %i\n", runList.count()); 160 for ( i = 0; i < runList.count(); ) 161 { 162 Win* w = GetWinByID( runList[i].wid ); 163 164 if ( w ) 165 { 166 w->EventTimer( runList[i].tid ); //... 167 i++; 168 } 169 else { runList.del( i ); } 170 } 171 172 //DWORD 173 unsigned minTim = 0xFFFF; 174 tim = GetTickMiliseconds(); 175 176 for ( i = 0, n = timerList.count(); i < n; i++ ) 177 { 178 TimerStruct* ts = timerList.ptr() + i; 179 //DWORD 180 unsigned t = tim - ts->last; 181 182 if ( t >= ts->period ) //! условие * 183 { 184 minTim = 0; 185 } 186 else 187 { 188 //DWORD 189 unsigned m = ts->period - t; 190 191 if ( minTim > m ) 192 { 193 minTim = m; 194 } 195 } 196 } 197 198 return minTim; 199 } 200 201 202 ////////////////////////////////////////////////// Win 203 204 EndModal(int id)205 void Win::EndModal( int id ) 206 { 207 if ( modal && !blockedBy ) 208 { 209 ( ( ModalStruct* )modal )->EndModal( id ); 210 } 211 } 212 213 Paint(GC & gc,const crect & paintRect)214 void Win::Paint( GC& gc, const crect& paintRect ) 215 { 216 gc.SetFillColor( 0xA0A0A0 ); 217 gc.FillRect( paintRect ); //CCC 218 } 219 220 IsEnabled()221 bool Win::IsEnabled() 222 { 223 for ( Win* p = this; p; p = p->parent ) 224 { 225 if ( !( p->state & S_ENABLED ) ) { return false; } 226 227 if ( p->IsModal() || p->Type() == Win::WT_MAIN ) { break; } 228 } 229 230 return true; 231 } 232 IsVisible()233 bool Win::IsVisible() 234 { 235 return ( state & S_VISIBLE ) != 0; 236 } 237 Enable(bool en)238 void Win::Enable( bool en ) 239 { 240 if ( en ) 241 { 242 SetState( S_ENABLED ); 243 } 244 else 245 { 246 ClearState( S_ENABLED ); 247 } 248 249 if ( IsVisible() ) 250 { 251 Invalidate(); 252 } 253 } 254 SetTimer(int id,unsigned period)255 void Win::SetTimer( int id, unsigned period ) 256 { 257 TimerReset/*Append*/( GetID(), id, period ); 258 } 259 ResetTimer(int id,unsigned period)260 void Win::ResetTimer( int id, unsigned period ) 261 { 262 TimerReset( GetID(), id, period ); 263 } 264 DelTimer(int id)265 void Win::DelTimer( int id ) 266 { 267 TimerDel( GetID(), id ); 268 } 269 DelAllTimers()270 void Win::DelAllTimers() 271 { 272 TimerDel( GetID() ); 273 } 274 Event(cevent * pEvent)275 bool Win::Event( cevent* pEvent ) 276 { 277 switch ( pEvent->Type() ) 278 { 279 case EV_KEYUP: 280 case EV_KEYDOWN: 281 return EventKey( ( cevent_key* )pEvent ); 282 283 case EV_CLOSE: 284 return EventClose(); 285 286 case EV_SETFOCUS: 287 { 288 // Invalidate(); 289 return EventFocus( true ); 290 } 291 292 case EV_KILLFOCUS: 293 // Invalidate(); 294 return EventFocus( false ); 295 296 case EV_SHOW: 297 return EventShow( ( ( cevent_show* )pEvent )->Show() ); 298 299 case EV_MOUSE_PRESS: 300 if ( ( whint & WH_CLICKFOCUS ) != 0 && !InFocus() ) 301 { 302 SetFocus(); 303 } 304 305 case EV_MOUSE_MOVE: 306 case EV_MOUSE_RELEASE: 307 case EV_MOUSE_DOUBLE: 308 return EventMouse( ( cevent_mouse* )pEvent ); 309 310 case EV_ENTER: 311 case EV_LEAVE: 312 EventEnterLeave( pEvent ); 313 return true; 314 315 case EV_SIZE: 316 RecalcLayouts(); 317 EventSize( ( cevent_size* )pEvent ); 318 return true; 319 320 case EV_MOVE: 321 EventMove( ( cevent_move* )pEvent ); 322 return true; 323 324 case EV_ACTIVATE: 325 return EventActivate( ( ( cevent_activate* )pEvent )->Activated(), ( ( cevent_activate* )pEvent )->Who() ); 326 327 default: 328 return false; 329 } 330 } 331 332 333 EventMouse(cevent_mouse * pEvent)334 bool Win::EventMouse( cevent_mouse* pEvent ) { return false; } EventKey(cevent_key * pEvent)335 bool Win::EventKey( cevent_key* pEvent ) { return false;} 336 EventChildKey(Win * child,cevent_key * pEvent)337 bool Win::EventChildKey( Win* child, cevent_key* pEvent ) 338 { 339 //dbg_printf("Win::EventChildKey key=0x%x mod=%d\n", pEvent->Key(), pEvent->Mod()); 340 // check if any child recognizes the key as its hot key 341 if ( ( pEvent->Mod() & KM_ALT ) != 0 ) 342 { 343 for ( int i = 0; i < childList.count(); i++ ) 344 { 345 Win* tchild = childList[i]; 346 Win* tHotkeyWin; 347 348 if ( ( tHotkeyWin = tchild->IsHisHotKey( pEvent ) ) != 0 ) 349 { 350 tHotkeyWin->SetFocus(); 351 return tHotkeyWin->EventKey( pEvent ); 352 } 353 } 354 } 355 356 return false; 357 } 358 EventFocus(bool recv)359 bool Win::EventFocus( bool recv ) 360 { 361 if ( recv && lastFocusChild ) 362 { 363 Win* w = GetWinByID( lastFocusChild ); 364 365 //printf("SET FOCUS TO LAST FOCUS CHILD (%p)\n",w); 366 if ( w ) { w->SetFocus(); } 367 } 368 369 return false; 370 } 371 EventClose()372 bool Win::EventClose() { if ( this->IsModal() ) { EndModal( CMD_CANCEL ); } return true;} EventShow(bool)373 bool Win::EventShow( bool ) { return true; } EventTimer(int tid)374 void Win::EventTimer( int tid ) {}; EventActivate(bool activated,Win * w)375 bool Win::EventActivate( bool activated, Win* w ) { return false; } EventEnterLeave(cevent * pEvent)376 void Win::EventEnterLeave( cevent* pEvent ) {} EventSize(cevent_size * pEvent)377 void Win::EventSize( cevent_size* pEvent ) {} EventMove(cevent_move * pEvent)378 void Win::EventMove( cevent_move* pEvent ) {} ThreadSignal(int id,int data)379 void Win::ThreadSignal( int id, int data ) {} ThreadStopped(int id,void * data)380 void Win::ThreadStopped( int id, void* data ) {} 381 Command(int id,int subId,Win * win,void * data)382 bool Win::Command( int id, int subId, Win* win, void* data ) 383 { 384 return parent ? parent->Command( id, subId, win, data ) : false; 385 } 386 Broadcast(int id,int subId,Win * win,void * data)387 bool Win::Broadcast( int id, int subId, Win* win, void* data ) 388 { 389 return false; 390 } 391 392 SendBroadcast(int id,int subId,Win * win,void * data,int level)393 int Win::SendBroadcast( int id, int subId, Win* win, void* data, int level ) 394 { 395 if ( level <= 0 ) { return 0; } 396 397 level--; 398 ccollect<WinID> list; 399 int n = 0; 400 int i; 401 402 for ( i = 0; i < childList.count(); i++ ) 403 { 404 list.append( childList[i]->GetID() ); 405 } 406 407 for ( i = 0; i < list.count(); i++ ) 408 { 409 Win* w = GetWinByID( list[i] ); 410 411 if ( w ) { n += w->SendBroadcast( id, subId, win, data, level ); } 412 } 413 414 if ( Broadcast( id, subId, win, data ) ) { n++; } 415 416 return n; 417 } 418 SetIdealSize()419 void Win::SetIdealSize() 420 { 421 if ( lSize.x.ideal > 0 && lSize.y.ideal > 0 ) 422 { 423 crect r = ScreenRect(); 424 crect cr = ClientRect(); 425 426 int xplus = ( r.right - r.left + 1 ) - ( cr.right - cr.left + 1 ); 427 int yplus = ( r.bottom - r.top + 1 ) - ( cr.bottom - cr.top + 1 ); 428 Move( crect( r.left, r.top, r.left + lSize.x.ideal + xplus, r.top + lSize.y.ideal + yplus ) ); //??? 429 } 430 } 431 432 UnblockTree(WinID id)433 bool Win::UnblockTree( WinID id ) 434 { 435 if ( blockedBy != id ) 436 { 437 return false; 438 } 439 440 blockedBy = 0; 441 442 for ( int i = 0; i < childList.count(); i++ ) 443 { 444 childList[i]->UnblockTree( id ); 445 } 446 447 return true; 448 } 449 450 IsOneParentWith(WinID h)451 bool Win::IsOneParentWith( WinID h ) 452 { 453 Win* w = GetWinByID( h ); 454 455 if ( !w ) { return false; } 456 457 while ( w->Parent() ) { w = w->Parent(); } 458 459 Win* t = this; 460 461 while ( t->Parent() ) { t = t->Parent(); } 462 463 return t == w; 464 } 465 PopupTreeList(ccollect<WinID> & list)466 void Win::PopupTreeList( ccollect<WinID>& list ) 467 { 468 if (type & Win::WT_POPUP) 469 list.append(handle); 470 for (int i = 0; i < childList.count(); i++) 471 childList[i]->PopupTreeList(list); 472 } 473 FocusNPChild(bool next)474 Win* Win::FocusNPChild( bool next ) 475 { 476 WinID c = lastFocusChild; 477 Win** list = childList.ptr(); 478 int count = childList.count(); 479 int i = 0; 480 Win* p = 0; 481 482 for ( i = 0; i < count; i++ ) 483 if ( list[i]->handle == c ) 484 { 485 p = list[i]; 486 break; 487 }; 488 489 if ( p ) 490 { 491 int n = i; 492 493 if ( next ) 494 { 495 for ( i = n + 1; i < count; i++ ) 496 if ( ( list[i]->whint & WH_TABFOCUS ) && list[i]->IsVisible() ) 497 { 498 list[i]->SetFocus(); 499 return list[i]; 500 } 501 502 for ( i = 0; i < n; i++ ) 503 if ( ( list[i]->whint & WH_TABFOCUS ) && list[i]->IsVisible() ) 504 { 505 list[i]->SetFocus(); 506 return list[i]; 507 } 508 } 509 else 510 { 511 for ( i = n - 1; i >= 0; i-- ) 512 if ( ( list[i]->whint & WH_TABFOCUS ) && list[i]->IsVisible() ) 513 { 514 list[i]->SetFocus(); 515 return list[i]; 516 } 517 518 for ( i = count - 1; i > n; i-- ) 519 if ( ( list[i]->whint & WH_TABFOCUS ) && list[i]->IsVisible() ) 520 { 521 list[i]->SetFocus(); 522 return list[i]; 523 } 524 } 525 526 if ( !p->InFocus() ) 527 { 528 p->SetFocus(); 529 } 530 531 return p; 532 533 } 534 else 535 { 536 for ( i = 0; i < count; i++ ) 537 if ( ( list[i]->whint & WH_TABFOCUS ) && list[i]->IsVisible() ) 538 { 539 list[i]->SetFocus(); 540 return list[i]; 541 } 542 } 543 544 return 0; 545 } 546 547 OnChangeStyles()548 void Win::OnChangeStyles() 549 { 550 } 551 StylesChanged(Win * w)552 void Win::StylesChanged( Win* w ) 553 { 554 if ( !w ) { return; } 555 556 int count = w->ChildCount(); 557 558 for ( int i = 0; i < count; i++ ) 559 { 560 Win* ch = w->GetChild( i ); 561 562 if ( !ch ) { break; } 563 564 StylesChanged( ch ); 565 }; 566 567 w->OnChangeStyles(); 568 569 w->RecalcLayouts(); 570 571 w->Invalidate(); 572 } 573 GetChildFont(Win * w,int fontId)574 cfont* Win::GetChildFont( Win* w, int fontId ) 575 { 576 return parent ? parent->GetChildFont( w, fontId ) : SysGetFont( w, fontId ); 577 } 578 ThreadCreate(int id,void * (* f)(void *),void * d)579 void Win::ThreadCreate( int id, void* ( *f )( void* ), void* d ) 580 { 581 wth_CreateThread( this, id, f, d ); 582 } 583 584 585 ColorTone(unsigned color,int tone)586 unsigned ColorTone( unsigned color, int tone /*0-255*/ ) 587 { 588 unsigned char R = ( unsigned char )( color % 0x100 ), G = ( unsigned char )( ( color / 0x100 ) % 0x100 ), B = ( unsigned char )( ( color / 0x10000 ) % 0x100 ); 589 590 if ( tone >= 0 ) 591 { 592 unsigned char t = tone % 0x100; 593 R += ( ( 0x100 - R ) * t ) / 0x100; 594 G += ( ( 0x100 - G ) * t ) / 0x100; 595 B += ( ( 0x100 - B ) * t ) / 0x100; 596 } 597 else 598 { 599 unsigned char t = ( -tone ) % 0x100; 600 R -= ( ( R * t ) / 0x100 ); 601 G -= ( ( G * t ) / 0x100 ); 602 B -= ( ( B * t ) / 0x100 ); 603 } 604 605 return ( ( B % 0x100 ) << 16 ) + ( ( G % 0x100 ) << 8 ) + ( R % 0x100 ); 606 } 607 DrawPixelList(GC & gc,unsigned short * s,int x,int y,unsigned color)608 void DrawPixelList( GC& gc, unsigned short* s, int x, int y, unsigned color ) 609 { 610 int n = *( s++ ); 611 612 for ( int i = 0; i < n; i++, s++, y++ ) 613 { 614 unsigned c = *s; 615 616 for ( int j = 0; j < 16; j++, c >>= 1 ) 617 if ( c & 1 ) { gc.SetPixel( x + j, y, color ); } 618 } 619 } 620 621 622 623 624 /////////////////////////////////////// cevent's 625 ~cevent()626 cevent::~cevent() {} ~cevent_show()627 cevent_show::~cevent_show() {} ~cevent_input()628 cevent_input::~cevent_input() {} ~cevent_key()629 cevent_key::~cevent_key() {} ~cevent_mouse()630 cevent_mouse::~cevent_mouse() {} ~cevent_activate()631 cevent_activate::~cevent_activate() {} ~cevent_size()632 cevent_size::~cevent_size() {} ~cevent_move()633 cevent_move::~cevent_move() {} 634 635 /////////////////////////////////////// Win Threads 636 637 WthInternalEvent wthInternalEvent; 638 639 enum WTHCMD 640 { 641 WTH_CMD_NONE = 0, 642 WTH_CMD_EVENT = 1, 643 WTH_CMD_END = 2 644 }; 645 646 struct WTHNode 647 { 648 volatile thread_t th; 649 volatile int id; 650 Win* volatile w; 651 volatile int data; 652 void* ( *volatile func )( void* ); 653 void* volatile fData; 654 volatile int cmd; 655 WTHNode* volatile thNext; 656 WTHNode* volatile winNext; 657 WTHNode* volatile cmdNext; WTHNodewal::WTHNode658 WTHNode(): id( 0 ), w( 0 ), data( 0 ), func( 0 ), fData( 0 ), cmd( 0 ), thNext( 0 ), winNext( 0 ), cmdNext( 0 ) {} 659 }; 660 th_key(thread_t th)661 inline unsigned th_key( thread_t th ) 662 { 663 unsigned key = 0; 664 665 for ( size_t i = 0; i < sizeof( th ); i++ ) { key += ( ( unsigned char* )&th )[i]; } 666 667 return key; 668 } 669 win_key(Win * w)670 inline unsigned win_key( Win* w ) 671 { 672 return ( unsigned )( w - ( Win* )0 ); 673 } 674 675 class WTHash 676 { 677 friend void wth_DropWindow( Win* w ); 678 friend void wth_CreateThread( Win* w, int id, void* ( *f )( void* ), void* d ); 679 friend bool WinThreadSignal( int data ); 680 friend void* _swl_win_thread_func( void* data ); 681 friend void wth_DoEvents(); 682 683 #define WTH_HASH_SIZE (331) 684 WTHNode* volatile thList[WTH_HASH_SIZE]; 685 WTHNode* volatile winList[WTH_HASH_SIZE]; 686 WTHNode* volatile cmdFirst; 687 WTHNode* volatile cmdLast; 688 689 Mutex mutex; 690 public: WTHash()691 WTHash() 692 : cmdFirst( 0 ), cmdLast( 0 ) 693 { 694 int i; 695 696 for ( i = 0; i < WTH_HASH_SIZE; i++ ) { thList[i] = 0; } 697 698 for ( i = 0; i < WTH_HASH_SIZE; i++ ) { winList[i] = 0; } 699 } ~WTHash()700 ~WTHash() {} 701 } wtHash; 702 703 _swl_win_thread_func(void * data)704 void* _swl_win_thread_func( void* data ) 705 { 706 WTHNode* p = ( ( WTHNode* )data ); 707 void* ret = p->func( p->fData ); 708 709 MutexLock lock( &wtHash.mutex ); 710 unsigned tN = th_key( p->th ) % WTH_HASH_SIZE; 711 712 WTHNode* volatile* t = &( wtHash.thList[tN] ); 713 714 while ( *t ) 715 { 716 if ( t[0] == p ) 717 { 718 t[0] = p->thNext; 719 p->thNext = 0; 720 break; 721 } 722 723 t = &( t[0]->thNext ); 724 } 725 726 if ( !p->cmd ) 727 { 728 p->cmdNext = 0; 729 730 if ( wtHash.cmdLast ) 731 { 732 wtHash.cmdLast->cmdNext = p; 733 } 734 else 735 { 736 wtHash.cmdFirst = p; 737 } 738 739 wtHash.cmdLast = p; 740 } 741 742 p->cmd = WTH_CMD_END; 743 744 try 745 { 746 wthInternalEvent.SetSignal(); 747 } 748 catch ( cexception* e ) //??? 749 { 750 e->destroy(); 751 } 752 753 return ret; 754 } 755 wth_CreateThread(Win * w,int id,void * (* f)(void *),void * d)756 void wth_CreateThread( Win* w, int id, void* ( *f )( void* ), void* d ) 757 { 758 WTHNode* p = new WTHNode; 759 p->w = w; 760 p->id = id; 761 p->func = f; 762 p->fData = d; 763 MutexLock lock( &wtHash.mutex ); 764 765 int err = thread_create( const_cast<thread_t*>( &( p->th ) ), _swl_win_thread_func, p ); 766 767 if ( err ) { throw_syserr( err, "can`t create window thread" ); } 768 769 unsigned tN = th_key( p->th ) % WTH_HASH_SIZE; 770 unsigned wN = win_key( w ) % WTH_HASH_SIZE; 771 p->winNext = wtHash.winList[wN]; 772 wtHash.winList[wN] = p; 773 p->thNext = wtHash.thList[tN]; 774 wtHash.thList[tN] = p; 775 } 776 WinThreadSignal(int data)777 bool WinThreadSignal( int data ) 778 { 779 thread_t th = thread_self(); 780 unsigned n = th_key( th ) % WTH_HASH_SIZE; 781 //printf("Find tn=%i (%p)\n", n, th); 782 MutexLock lock( &wtHash.mutex ); 783 784 wthInternalEvent.SetSignal(); 785 786 for ( WTHNode* p = wtHash.thList[n]; p; p = p->thNext ) 787 if ( thread_equal( th, p->th ) ) 788 { 789 if ( !p->cmd ) 790 { 791 p->cmdNext = 0; 792 793 if ( wtHash.cmdLast ) 794 { 795 wtHash.cmdLast->cmdNext = p; 796 } 797 else 798 { 799 wtHash.cmdFirst = p; 800 } 801 802 wtHash.cmdLast = p; 803 } 804 805 p->cmd = WTH_CMD_EVENT; 806 p->data = data; 807 808 return p->w != 0; 809 } 810 811 //printf("thread not found %p\n", th); 812 return false; 813 } 814 wth_DropWindow(Win * w)815 void wth_DropWindow( Win* w ) 816 { 817 MutexLock lock( &wtHash.mutex ); 818 unsigned n = win_key( w ) % WTH_HASH_SIZE; 819 WTHNode* volatile* p = &( wtHash.winList[n] ); 820 821 while ( *p ) 822 { 823 if ( p[0]->w == w ) 824 { 825 p[0]->w = 0; 826 WTHNode* t = p[0]; 827 p[0] = p[0]->winNext; 828 t->winNext = 0; 829 } 830 else { p = &( p[0]->winNext ); } 831 } 832 } 833 834 wth_DoEvents()835 void wth_DoEvents() 836 { 837 WTHNode* last = 0; 838 839 { 840 MutexLock lock( &wtHash.mutex ); 841 last = wtHash.cmdLast; 842 wthInternalEvent.ClearSignal(); 843 } 844 845 if ( !last ) { return; } 846 847 while ( true ) 848 { 849 MutexLock lock( &wtHash.mutex ); 850 WTHNode* p = wtHash.cmdFirst; 851 852 if ( !p ) { break; } //botva? 853 854 if ( p->cmd == WTH_CMD_END ) 855 { 856 if ( p->w ) 857 { 858 unsigned n = win_key( p->w ) % WTH_HASH_SIZE; 859 860 for ( WTHNode * volatile* pp = &( wtHash.winList[n] ); pp[0]; pp = &( pp[0]->winNext ) ) 861 if ( pp[0] == p ) 862 { 863 pp[0] = p->winNext; 864 break; 865 } 866 } 867 868 wtHash.cmdFirst = p->cmdNext; 869 870 if ( !wtHash.cmdFirst ) { wtHash.cmdLast = 0; } 871 872 lock.Unlock(); 873 874 try 875 { 876 void* ret = 0; 877 thread_join( p->th, &ret ); 878 879 if ( p->w != 0 ) 880 { 881 p->w->ThreadStopped( p->id, ret ); 882 } 883 884 //printf("End of Thread Win=%p, id=%i, ret = %p\n", p->w, p->id, ret); 885 886 } 887 catch ( ... ) 888 { 889 delete p; 890 }; 891 892 delete p; 893 894 } 895 else if ( p->cmd == WTH_CMD_EVENT ) 896 { 897 Win* w = p->w; 898 int id = p->id; 899 int data = p->data; 900 p->cmd = 0; 901 wtHash.cmdFirst = p->cmdNext; 902 903 if ( !wtHash.cmdFirst ) { wtHash.cmdLast = 0; } 904 905 lock.Unlock(); 906 907 if ( w ) 908 { 909 w->ThreadSignal( id, data ); 910 } 911 912 //printf("Thread Evant Win=%p, id=%i, data=%i\n",w,id,data); 913 914 } 915 else 916 { 917 fprintf( stderr, "bad state in void wth_DoEvents()\n" ); 918 } 919 920 if ( p == last ) { break; } 921 } 922 } 923 924 925 ///////////////////////////////////////////// ClipboardText 926 CopyFrom(const ClipboardText & a)927 void ClipboardText::CopyFrom( const ClipboardText& a ) 928 { 929 Clear(); 930 int i; 931 932 for ( i = 0; i < a.list.count(); i++ ) 933 { 934 std::vector<unicode_t> p( BUF_SIZE ); 935 memcpy( p.data(), a.list.const_item( i ).data(), BUF_SIZE * sizeof( unicode_t ) ); 936 list.append( p ); 937 } 938 939 count = a.count; 940 } 941 ClipboardText()942 ClipboardText::ClipboardText() 943 : count( 0 ) 944 { 945 } 946 ClipboardText(const ClipboardText & a)947 ClipboardText::ClipboardText( const ClipboardText& a ) 948 : count( 0 ) 949 { 950 CopyFrom( a ); 951 } 952 operator =(const ClipboardText & a)953 ClipboardText& ClipboardText::operator = ( const ClipboardText& a ) 954 { 955 CopyFrom( a ); 956 return *this; 957 } 958 959 Clear()960 void ClipboardText::Clear() 961 { 962 list.clear(); 963 count = 0; 964 } 965 Append(unicode_t c)966 void ClipboardText::Append( unicode_t c ) 967 { 968 int n = count + 1; 969 int bc = ( n + BUF_SIZE - 1 ) / BUF_SIZE; 970 971 while ( list.count() < bc ) 972 { 973 std::vector<unicode_t> p( BUF_SIZE ); 974 list.append( p ); 975 } 976 977 count++; 978 n = count - 1; 979 980 list[n / BUF_SIZE][n % BUF_SIZE] = c; 981 } 982 AppendUnicodeStr(const unicode_t * c)983 void ClipboardText::AppendUnicodeStr( const unicode_t* c ) 984 { 985 while ( c && *c ) 986 { 987 this->Append( *c ); 988 c++; 989 } 990 } 991 992 ///////////////////////////////// Image32 ///////////////////////////// 993 alloc(int w,int h)994 void Image32::alloc( int w, int h ) 995 { 996 std::vector<uint32_t> d( w * h ); 997 998 _data = d; 999 _width = w; 1000 _height = h; 1001 } 1002 clear()1003 void Image32::clear() { _width = _height = 0; _data.clear(); } 1004 fill(int left,int top,int right,int bottom,unsigned c)1005 void Image32::fill( int left, int top, int right, int bottom, unsigned c ) 1006 { 1007 if ( left < 0 ) { left = 0; } 1008 1009 if ( right > _width ) { right = _width; } 1010 1011 if ( top < 0 ) { top = 0; } 1012 1013 if ( bottom > _height ) { bottom = _height; } 1014 1015 if ( left >= right || top >= bottom ) { return; } 1016 1017 for ( int i = top; i < bottom; i++ ) 1018 { 1019 uint32_t* p = &_data[i * _width]; 1020 uint32_t* end = p + right; 1021 p += left; 1022 1023 for ( ; p < end; p++ ) { *p = c; } 1024 } 1025 } 1026 copy(const Image32 & a)1027 void Image32::copy( const Image32& a ) 1028 { 1029 if ( a._width != _width || a._height != _height ) { alloc( a._width, a._height ); } 1030 1031 if ( _width > 0 && _height > 0 ) 1032 { 1033 memcpy( _data.data(), a._data.data(), _width * _height * sizeof( uint32_t ) ); 1034 } 1035 } 1036 1037 1038 #define FROM_RGBA32(src,R,G,B,A) { A = ((src)>>24)&0xFF; B=((src)>>16)&0xFF; G=((src)>>8)&0xFF; R=(src)&0xFF; } 1039 #define FROM_RGBA32_PLUS(src,R,G,B,A) { A += ((src)>>24)&0xFF; B+=((src)>>16)&0xFF; G+=((src)>>8)&0xFF; R+=(src)&0xFF; } 1040 #define TO_RGBA32(R,G,B,A,n) ((((A)/(n))&0xFF)<<24) | ((((B)/(n))&0xFF)<<16) | ((((G)/(n))&0xFF)<<8) | ((((R)/(n))&0xFF)) 1041 copy(const Image32 & a,int w,int h)1042 void Image32::copy( const Image32& a, int w, int h ) 1043 { 1044 if ( a._width == w && a._height == h ) 1045 { 1046 copy( a ); 1047 return; 1048 } 1049 1050 if ( !w || !h ) 1051 { 1052 clear(); 1053 return; 1054 } 1055 1056 alloc( w, h ); 1057 1058 if ( a._width <= 0 || a._height <= 0 ) { return; } 1059 1060 //упрощенная схема, не очень качественно, зато быстро 1061 1062 std::vector< std::pair<int, int> > p( w ); 1063 1064 int x; 1065 int wN = a._width / w; 1066 int wN2 = wN / 2; 1067 1068 for ( x = 0; x < w; x++ ) 1069 { 1070 int t = ( x * a._width ) / w; 1071 int t1 = t - wN2; 1072 int t2 = t1 + wN; 1073 1074 if ( t2 == t1 ) { t2 = t1 + 1; } 1075 1076 p[x].first = ( t1 >= 0 ) ? t1 : 0; 1077 p[x].second = ( t2 <= a._width ) ? t2 : a._width; 1078 } 1079 1080 int hN = a._height / h; 1081 1082 int y; 1083 1084 for ( y = 0; y < h; y++ ) 1085 { 1086 1087 uint32_t* line = &_data[y * _width]; 1088 int hN2 = hN / 2; 1089 1090 if ( !hN ) 1091 { 1092 const uint32_t* a_line = &a._data[ ( ( y * a._height ) / h ) * a._width ]; 1093 1094 if ( !wN ) 1095 for ( x = 0; x < w; x++ ) { line[x] = a_line[p[x].first]; } 1096 else 1097 { 1098 for ( x = 0; x < w; x++ ) 1099 { 1100 unsigned R, G, B, A; 1101 int n1 = p[x].first; 1102 int n2 = p[x].second; 1103 FROM_RGBA32( a_line[n1], R, G, B, A ); 1104 1105 for ( int i = n1 + 1; i < n2; i++ ) { FROM_RGBA32_PLUS( a_line[i], R, G, B, A ); } 1106 1107 n2 -= n1; 1108 line[x] = n2 ? TO_RGBA32( R, G, B, A, n2 ) : 0xFF; 1109 } 1110 } 1111 } 1112 else 1113 { 1114 1115 int t = ( y * a._height ) / h; 1116 int t1 = t - hN2; 1117 int t2 = t1 + hN; 1118 1119 if ( t1 < 0 ) { t1 = 0; } 1120 1121 if ( t2 > a._height ) { t2 = a._height; } 1122 1123 for ( x = 0; x < w; x++ ) 1124 { 1125 1126 unsigned R = 0, G = 0, B = 0, A = 0; 1127 int n1 = p[x].first; 1128 int n2 = p[x].second; 1129 1130 for ( int iy = t1; iy < t2; iy++ ) 1131 { 1132 const uint32_t* a_line = &a._data[ iy * a._width ]; 1133 1134 for ( int i = n1; i < n2; i++ ) { FROM_RGBA32_PLUS( a_line[i], R, G, B, A ); } 1135 } 1136 1137 n2 -= n1; 1138 n2 *= ( t2 - t1 ); 1139 line[x] = n2 ? TO_RGBA32( R, G, B, A, n2 ) : 0xFF00; 1140 } 1141 } 1142 } 1143 } 1144 copy(const XPMImage & xpm)1145 void Image32::copy( const XPMImage& xpm ) 1146 { 1147 const unsigned* colors = xpm.Colors(); 1148 const int* data = xpm.Data(); 1149 clear(); 1150 int w = xpm.Width(); 1151 int h = xpm.Height(); 1152 1153 if ( w <= 0 || h <= 0 ) { return; } 1154 1155 alloc( w, h ); 1156 1157 for ( size_t i = 0; i != _data.size( ); i++, data++ ) 1158 { 1159 _data[i] = ( *data >= 0 ) ? colors[*data] : 0xFF000000; 1160 } 1161 } 1162 1163 1164 //////////// XPMImage 1165 Clear()1166 void XPMImage::Clear() 1167 { 1168 colors.clear(); 1169 colorCount = 0; 1170 none = -1; 1171 width = height = 0; 1172 data.clear(); 1173 } 1174 1175 struct color_tree_node 1176 { 1177 bool isColor; 1178 union 1179 { 1180 color_tree_node* p[0x100]; 1181 int c[0x100]; 1182 }; color_tree_nodewal::color_tree_node1183 color_tree_node( bool _is_color ) 1184 : isColor( _is_color ) 1185 { 1186 int i; 1187 1188 if ( _is_color ) { for ( i = 0; i < 0x100; i++ ) { c[i] = -1; } } 1189 else { for ( i = 0; i < 0x100; i++ ) { p[i] = 0; } } 1190 } 1191 ~color_tree_node(); 1192 }; 1193 ~color_tree_node()1194 color_tree_node::~color_tree_node() 1195 { 1196 if ( !isColor ) 1197 { 1198 for ( int i = 0; i < 0x100; i++ ) if ( p[i] ) { delete p[i]; } 1199 } 1200 } 1201 InsertColorId(color_tree_node * p,const char * s,int count,int colorId)1202 static void InsertColorId( color_tree_node* p, const char* s, int count, int colorId ) 1203 { 1204 if ( !p ) { return; } 1205 1206 while ( count > 0 ) 1207 { 1208 unsigned char n = *( s++ ); 1209 count--; 1210 1211 1212 if ( p->isColor ) 1213 { 1214 1215 if ( !count ) 1216 { 1217 p->c[n] = colorId; 1218 } 1219 1220 //else ignore 1221 1222 return; 1223 } 1224 else 1225 { 1226 if ( count ) 1227 { 1228 if ( !p->p[n] ) 1229 { 1230 p->p[n] = new color_tree_node( count == 1 ); 1231 } 1232 1233 p = p->p[n]; 1234 } 1235 else { return; } //else ignore 1236 } 1237 } 1238 } 1239 GetColorId(color_tree_node * p,const char * s,int count)1240 static int GetColorId( color_tree_node* p, const char* s, int count ) 1241 { 1242 while ( p && count > 0 ) 1243 { 1244 unsigned char n = *( s++ ); 1245 count--; 1246 1247 if ( p->isColor ) 1248 { 1249 return p->c[n]; 1250 } 1251 else 1252 { 1253 p = p->p[n]; 1254 } 1255 } 1256 1257 return -1; 1258 } 1259 SS(const char * & s)1260 inline void SS( const char*& s ) { while ( *s > 0 && *s <= 32 ) { s++; } } 1261 SInt(const char * & s)1262 static int SInt( const char*& s ) 1263 { 1264 int n = 0; 1265 1266 for ( ; *s && *s >= '0' && *s <= '9'; s++ ) 1267 { 1268 n = n * 10 + ( *s - '0' ); 1269 } 1270 1271 return n; 1272 } 1273 SHex(const char * & s)1274 static unsigned SHex( const char*& s ) 1275 { 1276 unsigned n = 0; 1277 1278 for ( ; *s; s++ ) 1279 { 1280 if ( *s >= '0' && *s <= '9' ) 1281 { 1282 n = ( n << 4 ) + ( *s - '0' ); 1283 } 1284 else if ( *s >= 'a' && *s <= 'f' ) 1285 { 1286 n = ( n << 4 ) + ( *s - 'a' ) + 10; 1287 } 1288 else if ( *s >= 'A' && *s <= 'F' ) 1289 { 1290 n = ( n << 4 ) + ( *s - 'A' ) + 10; 1291 } 1292 else { return n; } 1293 } 1294 1295 return n; 1296 } 1297 HSVtoRGB(unsigned hsv)1298 static unsigned HSVtoRGB( unsigned hsv ) 1299 { 1300 return hsv; //!!! 1301 } 1302 1303 Load(const char ** list,int count)1304 bool XPMImage::Load( const char** list, int count ) 1305 { 1306 Clear(); 1307 1308 if ( count < 1 ) 1309 { 1310 //printf("err 0\n"); 1311 return false; 1312 } 1313 1314 const char* s = list[0]; 1315 1316 list++; 1317 count--; 1318 1319 SS( s ); 1320 int w = SInt( s ); 1321 SS( s ); 1322 int h = SInt( s ); 1323 SS( s ); 1324 int nc = SInt( s ); 1325 SS( s ); 1326 int cpp = SInt( s ); 1327 1328 if ( !( w > 0 && h > 0 && nc > 0 && cpp > 0 ) || w > 16000 || h > 16000 || nc > 0xFFFFF || cpp > 4 ) 1329 { 1330 //printf("err 1\n"); 1331 return false; 1332 } 1333 1334 colors.resize( nc ); 1335 { 1336 for ( int i = 0; i < nc; i++ ) { colors[i] = 0; } 1337 } 1338 data.resize( w * h ); 1339 { 1340 int* p = data.data(); 1341 1342 for ( int n = w * h; n > 0; n--, p++ ) { *p = -1; } 1343 } 1344 1345 colorCount = nc; 1346 width = w; 1347 height = h; 1348 1349 1350 int i; 1351 1352 color_tree_node tree( cpp == 1 ); 1353 1354 for ( i = 0; i < nc && count > 0; i++, count--, list++ ) 1355 { 1356 const char* s = list[0]; 1357 int l = strlen( s ); 1358 1359 if ( l <= cpp ) 1360 { 1361 return false; 1362 //printf("err 2\n"); 1363 } 1364 1365 s += cpp; 1366 1367 1368 while ( *s ) 1369 { 1370 SS( s ); 1371 1372 if ( *s == 'c' ) 1373 { 1374 s++; 1375 SS( s ); 1376 1377 if ( *s == '#' ) 1378 { 1379 s++; 1380 unsigned c = SHex( s ); 1381 colors[i] = ( c & 0xFF00FF00 ) | ( ( c >> 16 ) & 0xFF ) | ( ( c << 16 ) & 0xFF0000 ); 1382 1383 } 1384 else if ( *s == '%' ) 1385 { 1386 s++; 1387 colors[i] = HSVtoRGB( SHex( s ) ); 1388 } 1389 else if ( ( s[0] == 'N' || s[0] == 'n' ) && 1390 ( s[1] == 'O' || s[1] == 'o' ) && 1391 ( s[2] == 'N' || s[2] == 'n' ) && 1392 ( s[3] == 'E' || s[3] == 'e' ) 1393 ) 1394 { 1395 s += 4; 1396 break; 1397 } 1398 else 1399 { 1400 //ignore 1401 while ( *s < 0 || *s > 32 ) { s++; } 1402 } 1403 1404 InsertColorId( &tree, list[0], cpp, i ); 1405 1406 break; 1407 } 1408 else 1409 { 1410 break; //ignore 1411 } 1412 }; 1413 1414 1415 } 1416 1417 int* dataPtr = data.data(); 1418 1419 for ( i = 0; i < h && count > 0; i++, count--, list++, dataPtr += width ) 1420 { 1421 const char* s = list[0]; 1422 int l = strlen( s ); 1423 int n = l / cpp; 1424 1425 for ( int j = 0; j < n; j++, s += cpp ) 1426 { 1427 int id = GetColorId( &tree, s, cpp ); 1428 //printf("%i,", id); 1429 dataPtr[j] = id; 1430 } 1431 } 1432 1433 return true; 1434 } 1435 1436 /////////////////////////// cicon ////////////////////////////////// 1437 1438 static std::unordered_map< int, ccollect< clPtr< cicon > > > cmdIconList; 1439 SetCmdIcon(int cmd,const Image32 & image,int w,int h)1440 void cicon::SetCmdIcon( int cmd, const Image32& image, int w, int h ) 1441 { 1442 MutexLock lock( &iconListMutex ); 1443 ccollect< clPtr<cicon> >& p = cmdIconList[cmd]; 1444 int n = p.count(); 1445 1446 clPtr<cicon> pIcon = new cicon(); 1447 pIcon->Load( image, w, h ); 1448 1449 for ( int i = 0; i < n; i++ ) 1450 { 1451 if ( p[i]->Width() == w && p[i]->Height() == h ) 1452 { 1453 p[i] = pIcon; 1454 return; 1455 } 1456 } 1457 1458 cmdIconList[cmd].append( pIcon ); 1459 } 1460 SetCmdIcon(int cmd,const char ** s,int w,int h)1461 void cicon::SetCmdIcon( int cmd, const char** s, int w, int h ) 1462 { 1463 XPMImage im; 1464 im.Load( s, 200000 ); 1465 Image32 image32; 1466 image32.copy( im ); 1467 cicon::SetCmdIcon( cmd, image32, w, h ); 1468 } 1469 1470 ClearCmdIcons(int cmd)1471 void cicon::ClearCmdIcons( int cmd ) 1472 { 1473 MutexLock lock( &iconListMutex ); 1474 cmdIconList.erase( cmd ); 1475 } 1476 IconDist(const cicon & a,int w,int h)1477 inline int IconDist( const cicon& a, int w, int h ) 1478 { 1479 w -= a.Width(); 1480 1481 if ( w < 0 ) { w = -w; } 1482 1483 h -= a.Height(); 1484 1485 if ( h < 0 ) { h = -h; } 1486 1487 return w + h; 1488 } 1489 1490 Load(int cmd,int w,int h)1491 void cicon::Load( int cmd, int w, int h ) 1492 { 1493 if ( data ) { Clear(); } 1494 1495 MutexLock lock( &iconListMutex ); 1496 1497 auto i = cmdIconList.find( cmd ); 1498 1499 if ( i == cmdIconList.end() ) { return; } 1500 1501 ccollect< clPtr<cicon> >* p = &( i->second ); 1502 1503 if ( !p ) { return; } 1504 1505 int n = p->count(); 1506 1507 if ( n <= 0 ) { return; } 1508 1509 clPtr<cicon>* t = p->ptr(); 1510 1511 cicon* minIcon = t[0].ptr(); 1512 t++; 1513 1514 int minDist = IconDist( *minIcon, w, h ); 1515 1516 1517 if ( !minDist ) 1518 { 1519 Copy( *minIcon ); 1520 return; 1521 } 1522 1523 for ( int i = 1; i < n; i++, t++ ) 1524 { 1525 int dist = IconDist( t[i].ptr()[0], w, h ); 1526 1527 if ( !dist ) 1528 { 1529 Copy( t[i].ptr()[0] ); 1530 return; 1531 } 1532 1533 if ( minDist > dist ) 1534 { 1535 minIcon = t[i].ptr(); 1536 minDist = dist; 1537 } 1538 } 1539 1540 Load( minIcon->data->image, w, h ); 1541 } 1542 Load(const char ** list,int w,int h)1543 void cicon::Load( const char** list, int w, int h ) 1544 { 1545 XPMImage xpm; 1546 xpm.Load( list, 100000 ); 1547 Image32 im; 1548 im.copy( xpm ); 1549 Load( im, w, h ); 1550 } 1551 Copy(const cicon & a)1552 void cicon::Copy( const cicon& a ) 1553 { 1554 if ( data ) { Clear(); } 1555 1556 if ( !a.data ) { return; } 1557 1558 MutexLock lock( &iconCopyMutex ); 1559 data = a.data; 1560 data->counter++; 1561 } 1562 Load(const Image32 & image,int w,int h)1563 void cicon::Load( const Image32& image, int w, int h ) 1564 { 1565 if ( data ) { Clear(); } 1566 1567 IconData* p = new IconData; 1568 1569 try 1570 { 1571 p->counter = 1; 1572 //printf("load cicon %i, %i\n", w, h); 1573 p->image.copy( image, w, h ); 1574 } 1575 catch ( ... ) 1576 { 1577 delete p; 1578 throw; 1579 } 1580 1581 data = p; 1582 } 1583 1584 Clear()1585 void cicon::Clear() 1586 { 1587 if ( data ) 1588 { 1589 MutexLock lock( &iconCopyMutex ); 1590 data->counter--; 1591 1592 if ( data->counter <= 0 ) { delete data; } 1593 1594 data = 0; 1595 } 1596 } 1597 1598 Dis(unsigned a)1599 inline unsigned Dis( unsigned a ) 1600 { 1601 unsigned b = ( ( a >> 16 ) & 0xFF ); 1602 unsigned g = ( ( a >> 8 ) & 0xFF ); 1603 unsigned r = ( ( a ) & 0xFF ); 1604 unsigned m = ( r + g + b ) / 2 + 30; 1605 1606 if ( m > 230 ) { m = 230; } 1607 1608 return ( a & 0xFF000000 ) + ( m << 16 ) + ( m << 8 ) + m; 1609 } 1610 MakeDisabledImage32(Image32 * dest,const Image32 & src)1611 void MakeDisabledImage32( Image32* dest, const Image32& src ) 1612 { 1613 if ( !dest ) { return; } 1614 1615 dest->copy( src ); 1616 int n = dest->height() * dest->width(); 1617 1618 if ( n <= 0 ) { return; } 1619 1620 uint32_t* p = dest->line( 0 ); 1621 1622 for ( ; n > 0; n--, p++ ) 1623 { 1624 *p = Dis( *p ); 1625 } 1626 } 1627 }; //namespace wal 1628 1629 namespace wal 1630 { 1631 1632 //////////////////////////// Ui 1633 UiCache()1634 UiCache::UiCache(): updated( false ) {} ~UiCache()1635 UiCache::~UiCache() {} 1636 GetUiID(const char * name)1637 int GetUiID( const char* name ) 1638 { 1639 static std::unordered_map< std::string, int> hash; 1640 static int id = 0; 1641 1642 auto i = hash.find( name ); 1643 1644 if ( i != hash.end() ) { return i->second; } 1645 1646 id++; 1647 hash[name] = id; 1648 1649 //printf("%3i '%s'\n", id, name); 1650 1651 return id; 1652 } 1653 1654 class UiStream 1655 { 1656 public: UiStream()1657 UiStream() {} 1658 enum { EOFCHAR = EOF }; 1659 virtual const char* Name(); 1660 virtual int Next(); 1661 virtual ~UiStream(); 1662 }; 1663 1664 class UiStreamFile: public UiStream 1665 { 1666 std::vector<sys_char_t> _name; 1667 std::string _name_utf8; 1668 BFile _f; 1669 public: UiStreamFile(const sys_char_t * s)1670 UiStreamFile( const sys_char_t* s ): _name( new_sys_str( s ) ), _name_utf8( sys_to_utf8( s ) ) { _f.Open( s ); } 1671 virtual const char* Name(); 1672 virtual int Next(); 1673 virtual ~UiStreamFile(); 1674 }; 1675 1676 class UiStreamMem: public UiStream 1677 { 1678 const char* s; 1679 public: UiStreamMem(const char * data)1680 UiStreamMem( const char* data ): s( data ) {} 1681 virtual int Next(); 1682 virtual ~UiStreamMem(); 1683 }; 1684 1685 Name()1686 const char* UiStream::Name() { return ""; } Next()1687 int UiStream::Next() { return EOFCHAR; } ~UiStream()1688 UiStream::~UiStream() {} 1689 Name()1690 const char* UiStreamFile::Name() { return _name_utf8.data(); } Next()1691 int UiStreamFile::Next() { return _f.GetC(); } ~UiStreamFile()1692 UiStreamFile::~UiStreamFile() {} 1693 Next()1694 int UiStreamMem::Next() { return *s ? *( s++ ) : EOF; } ~UiStreamMem()1695 UiStreamMem::~UiStreamMem() {} 1696 1697 1698 struct UiParzerBuf 1699 { 1700 std::vector<char> data; 1701 int size; 1702 int pos; UiParzerBufwal::UiParzerBuf1703 UiParzerBuf(): size( 0 ), pos( 0 ) {} Clearwal::UiParzerBuf1704 void Clear() { pos = 0; } 1705 void Append( int c ); 1706 }; 1707 Append(int c)1708 void UiParzerBuf::Append( int c ) 1709 { 1710 if ( pos >= size ) 1711 { 1712 int n = ( pos + 1 ) * 2; 1713 std::vector<char> p( n ); 1714 1715 if ( pos > 0 ) 1716 { 1717 memcpy( p.data(), data.data(), pos ); 1718 } 1719 1720 data = p; 1721 size = n; 1722 } 1723 1724 data[pos++] = c; 1725 } 1726 1727 1728 ///////////////////////////////// UiParzer 1729 class UiParzer 1730 { 1731 UiStream* _stream; 1732 int _cc; 1733 int _tok; 1734 int NextChar(); SS()1735 void SS() { while ( _cc >= 0 && _cc <= ' ' ) { NextChar(); } } 1736 UiParzerBuf _buf; 1737 int64_t _i; 1738 int _cline; 1739 public: 1740 enum TOKENS 1741 { 1742 TOK_ID = -500, // /[_\a][_\a\d]+/ 1743 TOK_STR, // "...\?..." 1744 TOK_INT, 1745 TOK_EOF 1746 }; 1747 1748 void Syntax( const char* s = "" ); 1749 UiParzer( UiStream* stream ); Tok() const1750 int Tok() const { return _tok; } Int() const1751 int64_t Int() const { return _i; } Str()1752 const char* Str() { return _buf.data.data(); } 1753 int Next(); 1754 void Skip( int tok ); 1755 void SkipAll( int tok, int mincount = 1 ); 1756 ~UiParzer(); 1757 }; 1758 Skip(int t)1759 void UiParzer::Skip( int t ) 1760 { 1761 if ( _tok != t ) 1762 { 1763 Syntax( GetFormattedString( "symbol not found '%c'", t ).c_str() ); 1764 } 1765 1766 Next(); 1767 } 1768 SkipAll(int t,int mincount)1769 void UiParzer::SkipAll( int t, int mincount ) 1770 { 1771 int n; 1772 1773 for ( n = 0; _tok == t; n++ ) { Next(); } 1774 1775 if ( n < mincount ) 1776 { 1777 Syntax( GetFormattedString( "symbol not found '%c'", t ).c_str() ); 1778 } 1779 } 1780 Syntax(const char * s)1781 void UiParzer::Syntax( const char* s ) 1782 { 1783 throw_msg( "Syntax error in '%s' line %i: %s", _stream->Name(), _cline + 1, s ); 1784 } 1785 UiParzer(UiStream * stream)1786 UiParzer::UiParzer( UiStream* stream ) 1787 : _stream( stream ), 1788 _cc( 0 ), 1789 _tok( 0 ), 1790 _cline( 0 ) 1791 { 1792 NextChar(); 1793 Next(); 1794 } 1795 ~UiParzer()1796 UiParzer::~UiParzer() {} 1797 NextChar()1798 int UiParzer::NextChar() 1799 { 1800 if ( _cc == UiStream::EOFCHAR ) 1801 { 1802 return _cc; 1803 } 1804 1805 _cc = _stream->Next(); 1806 1807 if ( _cc == '\n' ) { _cline++; } 1808 1809 return _cc; 1810 } 1811 1812 1813 Next()1814 int UiParzer::Next() 1815 { 1816 begin: 1817 SS(); 1818 1819 if ( _cc == '_' || IsAlpha( _cc ) ) 1820 { 1821 _buf.Clear(); 1822 _buf.Append( _cc ); 1823 NextChar(); 1824 1825 while ( IsAlpha( _cc ) || IsDigit( _cc ) || _cc == '_' || _cc == '-' ) 1826 { 1827 _buf.Append( _cc ); 1828 NextChar(); 1829 }; 1830 1831 _buf.Append( 0 ); 1832 1833 _tok = TOK_ID; 1834 1835 return _tok; 1836 } 1837 1838 if ( _cc == '/' ) 1839 { 1840 NextChar(); 1841 1842 if ( _cc != '/' ) 1843 { 1844 _tok = '/'; 1845 return _tok; 1846 } 1847 1848 //comment 1849 while ( _cc != UiStream::EOFCHAR && _cc != '\n' ) 1850 { 1851 NextChar(); 1852 } 1853 1854 goto begin; 1855 } 1856 1857 if ( _cc == '"' || _cc == '\'' ) 1858 { 1859 _buf.Clear(); 1860 int bc = _cc; 1861 NextChar(); 1862 1863 while ( _cc != bc ) 1864 { 1865 if ( _cc == UiStream::EOFCHAR ) 1866 { 1867 Syntax( "invalid string constant" ); 1868 } 1869 1870 if ( _cc == '\\' ) 1871 { 1872 NextChar(); 1873 1874 if ( _cc == UiStream::EOFCHAR ) 1875 { 1876 Syntax( "invalid string constant" ); 1877 } 1878 } 1879 1880 _buf.Append( _cc ); 1881 NextChar(); 1882 } 1883 1884 _buf.Append( 0 ); 1885 _tok = TOK_STR; 1886 NextChar(); 1887 return _tok; 1888 } 1889 1890 if ( IsDigit( _cc ) ) 1891 { 1892 int64_t n = 0; 1893 1894 if ( _cc == '0' ) 1895 { 1896 NextChar(); 1897 1898 1899 if ( _cc == 'x' || _cc == 'X' ) 1900 { 1901 NextChar(); 1902 1903 while ( true ) 1904 { 1905 if ( IsDigit( _cc ) ) 1906 { 1907 n = n * 16 + ( _cc - '0' ); 1908 } 1909 else if ( _cc >= 'a' && _cc <= 'f' ) 1910 { 1911 n = n * 16 + ( _cc - 'a' ) + 10; 1912 } 1913 else if ( _cc >= 'A' && _cc <= 'F' ) 1914 { 1915 n = n * 16 + ( _cc - 'A' ) + 10; 1916 } 1917 else 1918 { 1919 break; 1920 } 1921 1922 NextChar(); 1923 }; 1924 1925 _i = n; 1926 1927 _tok = TOK_INT; 1928 1929 return _tok; 1930 } 1931 } 1932 1933 for ( ; IsDigit( _cc ); NextChar() ) 1934 { 1935 n = n * 10 + ( _cc - '0' ); 1936 } 1937 1938 _i = n; 1939 _tok = TOK_INT; 1940 return _tok; 1941 }; 1942 1943 if ( _cc == UiStream::EOFCHAR ) 1944 { 1945 _tok = TOK_EOF; 1946 return _tok; 1947 } 1948 1949 _tok = _cc; 1950 NextChar(); 1951 return _tok; 1952 } 1953 Int()1954 int64_t UiValueNode::Int() 1955 { 1956 if ( !( flags & INT ) ) 1957 { 1958 if ( !( flags & STR ) ) { return 0; } 1959 1960 int64_t n = 0; 1961 const char* t = s.data(); 1962 1963 if ( !t || !*t ) { return 0; } 1964 1965 // bool minus = false; 1966 1967 if ( *t == '-' ) 1968 { 1969 // minus = true; 1970 t++; 1971 } 1972 1973 if ( *t == '+' ) { t++; } 1974 1975 for ( ; *t >= '0' && *t <= '9'; t++ ) { n = n * 10 + ( *t - '0' ); } 1976 1977 i = n; 1978 flags |= INT; 1979 } 1980 1981 return i; 1982 } 1983 Str()1984 const char* UiValueNode::Str() 1985 { 1986 if ( !( flags & STR ) ) 1987 { 1988 if ( !( flags & INT ) ) { return ""; } 1989 1990 s = ToString(i); 1991 flags |= STR; 1992 } 1993 1994 return s.data(); 1995 } 1996 1997 class UiValue; 1998 1999 struct UiSelector: public iIntrusiveCounter 2000 { 2001 struct Node 2002 { 2003 int idC; 2004 int idN; 2005 bool oneStep; Nodewal::UiSelector::Node2006 Node(): idC( 0 ), idN( 0 ), oneStep( true ) {} Nodewal::UiSelector::Node2007 Node( int c, int n, bool o ): idC( c ), idN( n ), oneStep( o ) {} 2008 }; 2009 2010 struct CondNode 2011 { 2012 bool no; 2013 int id; CondNodewal::UiSelector::CondNode2014 CondNode(): no( false ), id( 0 ) {} CondNodewal::UiSelector::CondNode2015 CondNode( bool n, int i ): no( n ), id( i ) {} 2016 }; 2017 2018 struct ValueNode 2019 { 2020 int id; 2021 UiValue* data; ValueNodewal::UiSelector::ValueNode2022 ValueNode(): id( 0 ), data( 0 ) {} ValueNodewal::UiSelector::ValueNode2023 ValueNode( int i, UiValue* v ): id( i ), data( v ) {} 2024 }; 2025 2026 ccollect<Node> stack; 2027 int item; 2028 ccollect<CondNode> cond; 2029 ccollect<ValueNode> val; 2030 2031 enum {CMPN = 4}; 2032 unsigned char cmpLev[CMPN]; 2033 Cmpwal::UiSelector2034 int Cmp( const clPtr<UiSelector>& a ) 2035 { 2036 int i = 0; 2037 2038 while ( i < CMPN && cmpLev[i] == a->cmpLev[i] ) { i++; } 2039 2040 return ( i >= CMPN ) ? 0 : cmpLev[i] < a->cmpLev[i] ? -1 : 1; 2041 }; 2042 AppendObjwal::UiSelector2043 void AppendObj( int c, int n, bool o ) 2044 { 2045 stack.append( Node( c, n, o ) ); 2046 2047 if ( n ) { cmpLev[0]++; } 2048 2049 if ( c ) { cmpLev[1]++; } 2050 } 2051 AppendCondwal::UiSelector2052 void AppendCond( bool no, int id ) { cond.append( CondNode( no, id ) ); cmpLev[3]++; } AppendValwal::UiSelector2053 void AppendVal( int id, UiValue* v ) { val.append( ValueNode( id, v ) ); } SetItemwal::UiSelector2054 void SetItem( int id ) {item = id; cmpLev[2] = id ? 1 : 0; } 2055 2056 UiSelectorwal::UiSelector2057 UiSelector(): item( 0 ) { for ( int i = 0; i < CMPN; i++ ) { cmpLev[i] = 0; } } 2058 2059 void Parze( UiParzer& parzer ); 2060 }; 2061 Parze(UiParzer & parzer)2062 void UiSelector::Parze( UiParzer& parzer ) 2063 { 2064 while ( true ) 2065 { 2066 bool oneStep = false; 2067 2068 if ( parzer.Tok() == '>' ) 2069 { 2070 oneStep = true; 2071 parzer.Next(); 2072 } 2073 2074 if ( parzer.Tok() == '*' ) 2075 { 2076 parzer.Next(); 2077 AppendObj( 0, 0, oneStep ); 2078 continue; 2079 } 2080 2081 int classId = 0; 2082 2083 if ( parzer.Tok() == UiParzer::TOK_ID ) 2084 { 2085 classId = GetUiID( parzer.Str() ); 2086 parzer.Next(); 2087 2088 } 2089 2090 int nameId = 0; 2091 2092 if ( parzer.Tok() == '#' ) 2093 { 2094 parzer.Next(); 2095 2096 if ( parzer.Tok() != UiParzer::TOK_ID ) 2097 { 2098 parzer.Syntax( "object name not found" ); 2099 } 2100 2101 nameId = GetUiID( parzer.Str() ); 2102 parzer.Next(); 2103 } 2104 2105 if ( !classId && !nameId ) { break; } 2106 2107 AppendObj( classId, nameId, oneStep ); 2108 } 2109 2110 if ( parzer.Tok() == '@' ) //item 2111 { 2112 parzer.Next(); 2113 2114 if ( parzer.Tok() != UiParzer::TOK_ID ) { parzer.Syntax( "item name not found" ); } 2115 2116 SetItem( item = GetUiID( parzer.Str() ) ); 2117 parzer.Next(); 2118 } 2119 2120 while ( parzer.Tok() == ':' ) 2121 { 2122 parzer.Next(); 2123 bool no = false; 2124 2125 if ( parzer.Tok() == '!' ) 2126 { 2127 parzer.Next(); 2128 no = true; 2129 } 2130 2131 if ( parzer.Tok() != UiParzer::TOK_ID ) { parzer.Syntax( "condition name not found" ); } 2132 2133 AppendCond( no, GetUiID( parzer.Str() ) ); 2134 parzer.Next(); 2135 } 2136 } 2137 ParzeNode(UiParzer & parzer)2138 bool UiValue::ParzeNode( UiParzer& parzer ) 2139 { 2140 if ( parzer.Tok() == UiParzer::TOK_INT ) 2141 { 2142 list.append( new UiValueNode( parzer.Int() ) ); 2143 } 2144 else if ( parzer.Tok() == UiParzer::TOK_STR ) 2145 { 2146 list.append( new UiValueNode( parzer.Str() ) ); 2147 } 2148 else 2149 { 2150 return false; 2151 } 2152 2153 parzer.Next(); 2154 return true; 2155 } 2156 Parze(UiParzer & parzer)2157 void UiValue::Parze( UiParzer& parzer ) 2158 { 2159 if ( parzer.Tok() == '(' ) 2160 { 2161 parzer.Next(); 2162 2163 while ( true ) 2164 { 2165 if ( !ParzeNode( parzer ) ) { break; } 2166 2167 if ( parzer.Tok() != ',' ) { break; } 2168 2169 parzer.Next(); 2170 }; 2171 2172 parzer.Skip( ')' ); 2173 } 2174 else 2175 { 2176 ParzeNode( parzer ); 2177 } 2178 } 2179 UiValue()2180 UiValue::UiValue() {} ~UiValue()2181 UiValue::~UiValue() {} 2182 2183 class UiRules: public iIntrusiveCounter 2184 { 2185 friend class UiCache; 2186 ccollect< clPtr<UiSelector>, 0x100> selectors; 2187 UiValue* values; 2188 public: UiRules()2189 UiRules(): values( 0 ) {} 2190 void Parze( UiParzer& parzer ); 2191 ~UiRules(); 2192 }; 2193 2194 2195 ~UiRules()2196 UiRules::~UiRules() 2197 { 2198 UiValue* v = values; 2199 2200 while ( v ) 2201 { 2202 UiValue* t = v; 2203 v = v->next; 2204 delete t; 2205 } 2206 } 2207 Parze(UiParzer & parzer)2208 void UiRules::Parze( UiParzer& parzer ) 2209 { 2210 while ( true ) 2211 { 2212 parzer.SkipAll( ';', 0 ); 2213 2214 if ( parzer.Tok() == UiParzer::TOK_EOF ) { break; } 2215 2216 ccollect< clPtr<UiSelector> > slist; 2217 2218 while ( true ) 2219 { 2220 if ( parzer.Tok() == '{' ) { break; } 2221 2222 clPtr<UiSelector> sel = new UiSelector(); 2223 slist.append( sel ); 2224 sel->Parze( parzer ); 2225 2226 int i = 0; 2227 2228 while ( i < selectors.count() ) 2229 { 2230 clPtr<UiSelector> other = selectors[i]; 2231 2232 if ( sel->Cmp( other ) >= 0 ) { break; } 2233 2234 i++; 2235 } 2236 2237 if ( i < selectors.count() ) 2238 { 2239 selectors.insert( i, sel ); 2240 } 2241 else 2242 { 2243 selectors.append( sel ); 2244 } 2245 2246 if ( parzer.Tok() != ',' ) { break; } 2247 2248 parzer.Next(); 2249 } 2250 2251 parzer.Skip( '{' ); 2252 2253 if ( !slist.count() ) { parzer.Syntax( "empty list of selectors" ); } 2254 2255 while ( true ) 2256 { 2257 if ( parzer.Tok() != UiParzer::TOK_ID ) { break; } 2258 2259 int id = GetUiID( parzer.Str() ); 2260 parzer.Next(); 2261 2262 parzer.Skip( ':' ); 2263 2264 values = new UiValue( values ); 2265 values->Parze( parzer ); 2266 2267 for ( int i = 0; i < slist.count(); i++ ) 2268 { 2269 slist[i]->AppendVal( id, values ); 2270 } 2271 2272 if ( parzer.Tok() == '}' ) { break; } 2273 2274 parzer.SkipAll( ';' ); 2275 } 2276 2277 parzer.Skip( '}' ); 2278 } 2279 } 2280 Update(UiRules & rules,ObjNode * orderList,int orderlistCount)2281 void UiCache::Update( UiRules& rules, ObjNode* orderList, int orderlistCount ) 2282 { 2283 //printf("UiCache::Update 1: %i\n", orderlistCount); 2284 hash.clear(); 2285 clPtr<UiSelector>* psl = rules.selectors.ptr(); 2286 int count = rules.selectors.count(); 2287 2288 for ( int i = 0; count > 0; count--, psl++, i++ ) 2289 { 2290 clPtr<UiSelector> s = rules.selectors.get( i ); 2291 int scount = s->stack.count(); 2292 2293 if ( scount > 0 ) 2294 { 2295 if ( orderlistCount > 0 ) 2296 { 2297 UiSelector::Node* sp = s->stack.ptr() + scount - 1; 2298 ObjNode* op = orderList; 2299 int n = orderlistCount; 2300 2301 bool oneStep = true; 2302 2303 while ( scount > 0 && n > 0 ) 2304 { 2305 if ( ( !sp->idC || sp->idC == op->classId ) && ( !sp->idN || sp->idN == op->nameId ) ) 2306 { 2307 oneStep = sp->oneStep; 2308 sp--; 2309 scount--; 2310 op++; 2311 n--; 2312 } 2313 else 2314 { 2315 if ( oneStep ) { break; } 2316 2317 op++; 2318 n--; 2319 } 2320 } 2321 2322 if ( scount <= 0 && s->val.count() ) 2323 { 2324 int count = s->val.count(); 2325 2326 //printf("'"); 2327 for ( int i = 0; i < count; i++ ) 2328 { 2329 hash[s->val[i].id].append( Node( s.ptr(), s->val[i].data ) ); 2330 //printf("*"); 2331 } 2332 2333 //printf("'\n"); 2334 } 2335 } 2336 } 2337 } 2338 2339 //printf("cache hash count=%i\n", hash.count()); 2340 updated = true; 2341 } 2342 2343 Get(int id,int item,int * condList)2344 UiValue* UiCache::Get( int id, int item, int* condList ) 2345 { 2346 auto i = hash.find( id ); 2347 2348 if ( i == hash.end() ) { return nullptr; } 2349 2350 ccollect<Node>* ids = &( i->second ); 2351 2352 if ( !ids ) { return nullptr; } 2353 2354 Node* p = ids->ptr(); 2355 int count = ids->count(); 2356 2357 for ( ; count > 0; count--, p++ ) 2358 { 2359 clPtr<UiSelector> s = p->s; 2360 2361 if ( !item && s->item ) { continue; } 2362 2363 if ( item && s->item && s->item != item ) { continue; } 2364 2365 int i; 2366 int n = s->cond.count(); 2367 2368 for ( i = 0; i < n; i++ ) 2369 { 2370 int cid = s->cond[i].id; 2371 bool no = s->cond[i].no; 2372 2373 bool found = false; 2374 2375 if ( condList ) 2376 { 2377 for ( int* t = condList; *t; t++ ) 2378 if ( *t == cid ) 2379 { 2380 found = true; 2381 break; 2382 } 2383 } 2384 2385 if ( found == no ) { break; } 2386 } 2387 2388 if ( i >= n ) { return p->v; } 2389 } 2390 2391 return 0; 2392 } 2393 2394 2395 static clPtr<UiRules> globalUiRules; 2396 ClearWinCache(const WINHASHNODE * pnode,void *)2397 static void ClearWinCache( const WINHASHNODE* pnode, void* ) 2398 { 2399 if ( pnode->win ) 2400 { 2401 pnode->win->UiCacheClear(); 2402 } 2403 } 2404 UiReadFile(const sys_char_t * fileName)2405 void UiReadFile( const sys_char_t* fileName ) 2406 { 2407 UiStreamFile stream( fileName ); 2408 UiParzer parzer( &stream ); 2409 2410 clPtr<UiRules> rules = new UiRules(); 2411 rules->Parze( parzer ); 2412 globalUiRules = rules; 2413 for ( const auto& i : winhash ) ClearWinCache( &(i.second), nullptr ); 2414 } 2415 UiReadMem(const char * s)2416 void UiReadMem( const char* s ) 2417 { 2418 UiStreamMem stream( s ); 2419 UiParzer parzer( &stream ); 2420 2421 clPtr<UiRules> rules = new UiRules(); 2422 rules->Parze( parzer ); 2423 globalUiRules = rules; 2424 for ( const auto& i : winhash ) ClearWinCache( &(i.second), nullptr ); 2425 } 2426 Set(int id,bool yes)2427 void UiCondList::Set( int id, bool yes ) 2428 { 2429 int i; 2430 2431 for ( i = 0; i < N; i++ ) if ( buf[i] == id ) { buf[i] = 0; } 2432 2433 if ( yes ) 2434 { 2435 for ( i = 0; i < N; i++ ) 2436 if ( !buf[i] ) 2437 { 2438 buf[i] = id; 2439 return; 2440 } 2441 } 2442 } 2443 2444 int uiColor = GetUiID( "color" ); 2445 int uiHotkeyColor = GetUiID( "hotkey-color" ); 2446 int uiBackground = GetUiID( "background" ); 2447 int uiFocusFrameColor = GetUiID( "focus-frame-color" ); 2448 int uiFrameColor = GetUiID( "frame-color" ); 2449 int uiButtonColor = GetUiID( "button-color" ); 2450 int uiMarkColor = GetUiID( "mark-color" ); 2451 int uiMarkBackground = GetUiID( "mark-background" ); 2452 int uiCurrentItem = GetUiID( "current-item" ); 2453 int uiCurrentItemFrame = GetUiID( "current-item-frame-color" ); 2454 int uiLineColor = GetUiID( "line-color" ); 2455 int uiPointerColor = GetUiID( "pointer-color" ); 2456 int uiOdd = GetUiID( "odd" ); 2457 2458 int uiVariable = GetUiID( "variable" ); 2459 int uiValue = GetUiID( "value" ); 2460 2461 int uiEnabled = GetUiID( "enabled" ); 2462 int uiFocus = GetUiID( "focus" ); 2463 int uiItem = GetUiID( "item" ); 2464 int uiClassWin = GetUiID( "Win" ); 2465 UiGetColor(int id,int itemId,UiCondList * cl,unsigned def)2466 unsigned Win::UiGetColor( int id, int itemId, UiCondList* cl, unsigned def ) 2467 { 2468 if ( !globalUiRules.ptr() ) { return def; } 2469 2470 int buf[0x100]; 2471 int pos = 0; 2472 2473 if ( cl ) 2474 { 2475 for ( int i = 0; i < UiCondList::N && i < 0x100 - 10; i++ ) 2476 if ( cl->buf[i] ) 2477 { 2478 buf[pos++] = cl->buf[i]; 2479 } 2480 } 2481 2482 if ( IsEnabled() ) 2483 { 2484 buf[pos++] = uiEnabled; 2485 } 2486 2487 if ( InFocus() ) 2488 { 2489 buf[pos++] = uiFocus; 2490 } 2491 2492 buf[pos++] = 0; 2493 2494 //printf("1\n"); 2495 if ( !uiCache.Updated() ) 2496 { 2497 //printf("2\n"); 2498 //Update(UiRules &rules, ObjNode *orderList, int orderlistCount) 2499 ccollect<UiCache::ObjNode> wlist; 2500 2501 for ( Win* w = this; w; w = w->Parent() ) 2502 { 2503 wlist.append( UiCache::ObjNode( w->UiGetClassId(), w->UiGetNameId() ) ); 2504 } 2505 2506 uiCache.Update( *globalUiRules.ptr(), wlist.ptr(), wlist.count() ); 2507 } 2508 2509 //printf("3\n"); 2510 UiValue* v = uiCache.Get( id, itemId, buf ); 2511 //printf("4 %p\n", v); 2512 //if (v) printf("5 %i\n", v->Int()); 2513 return v ? unsigned( v->Int() ) : def; 2514 }; 2515 UiGetClassId()2516 int Win::UiGetClassId() 2517 { 2518 return uiClassWin; 2519 } 2520 2521 } //namespace wal 2522