ICONLIST.CPP (33870B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 16 #ifdef WOLAPI_INTEGRATION 17 18 // Iconlist.cpp - created by ajw 07/07/98 19 20 // IconListClass is ListClass plus the option to include an icon on each line entry, 21 // the option to have the class maintain its own copies of strings passed to it 22 // for display, and the option to limit the maximum number of these strings that are 23 // kept (entries are removed from the top when this maximum is reached). 24 // Also added: multiple item selection capability. Note that the old selection code 25 // runs as normal, but it simply not used when it comes time to display. 26 // Also added: if mem. allocation is being done by this, the ability to break new items 27 // into multiple lines of text is enabled. 28 // Also added: extra data can be invisibly stored with each item, if memory allocation is 29 // being done by this. 30 // Extra data included 3 item preceding icons, 1 fixed position icon, an extra string, 31 // an extra void pointer, and a color remapping value. 32 33 #include "iconlist.h" 34 #include "dibapi.h" 35 36 int Format_Window_String_New( const char* string, int maxlinelen, int& width, int& height, char* szReturn, int iExtraChars ); 37 void CC_Draw_DIB( const char* pDIB, int xDest, int yDest, int iWidth, WindowNumberType window ); 38 39 //*********************************************************************************************** 40 IconListClass::IconListClass( int id, int x, int y, int w, int h, TextPrintType flags, void const * up, void const * down, 41 bool bResponsibleForStringAlloc, int iSelectionType, int iMaxItemsSaved ) : 42 ListClass( id, x, y, w, h, flags, up, down ) 43 { 44 // If bResponsibleForStringAlloc, COPIES of strings are stored in the list. Deletion is 45 // handled by this class. Icons are different - the caller is responsible for what's on 46 // the other end of the pointer. 47 bDoAlloc = bResponsibleForStringAlloc; 48 // iSelectionType = 0 for no selection shown, 1 for normal ListClass selection, 2 for n multiple selections 49 if( iSelectionType < 0 || iSelectionType > 2 ) iSelectionType = 1; 50 iSelectType = iSelectionType; 51 // If iMaxItemsSaved is 0, there is no limit to the number of text lines. The list can grow forever. 52 // Otherwise items are deleted from the head of the list when the maximum is passed. 53 // iMaxItemsSaved only applies when bResponsibleForStringAlloc. 54 iMaxItems = iMaxItemsSaved; 55 } 56 57 //*********************************************************************************************** 58 IconListClass::~IconListClass( void ) 59 { 60 // Delete the IconList_ItemExtras structs created to hold extra info on each item. 61 for( int i = 0; i < ExtrasList.Count(); i++ ) 62 delete (IconList_ItemExtras*)ExtrasList[ i ]; 63 64 if( bDoAlloc ) 65 { 66 // Delete all alloc'ed strings. 67 for( int i = 0; i < List.Count(); i++ ) 68 delete [] (char*)List[i]; 69 } 70 } 71 72 /*********************************************************************************************** 73 * IconListClass::Add_Item -- Adds an item to the list box. * 74 * * 75 * This will add the specified string to the list box. The string is added to the end * 76 * of the list. * 77 * * 78 * INPUT: text -- Pointer to the string to add to the list box. * 79 * pIcon -- Pointer to the shape to add. 80 * IconKind -- Indicates what type of image pIcon points to. 81 * szExtraDataString -- Extra string data that gets copied and stored along with item. 82 * szExtraDataPtr -- Extra data that gets stored along with item. 83 * pColorRemap -- Points to a color remapping used when drawing the item. 84 * 85 * OUTPUT: Returns new item index. * 86 * WARNINGS: none * 87 * HISTORY: 07/07/1998 ajw : Created. * 88 *=============================================================================================*/ 89 int IconListClass::Add_Item(char const * text) 90 { 91 return Add_Item( text, NULL, NULL, ICON_SHAPE ); 92 } 93 94 int IconListClass::Add_Item( const char* text, const char* szHelp, 95 void* pIcon0, ICONKIND IconKind0, const char* szExtraDataString /* = NULL */, 96 void* pvExtraDataPtr /* = NULL */, RemapControlType* pColorRemap /* = NULL */, 97 void* pIcon1 /* = NULL */, ICONKIND IconKind1 /* = ICON_SHAPE */, 98 void* pIcon2 /* = NULL */, ICONKIND IconKind2 /* = ICON_SHAPE */, 99 void* pFixedIcon /* = NULL */, ICONKIND FixedIconKind /* = ICON_SHAPE */, int iXFixedIcon /* = 0 */, int iYFixedIcon /* = 0 */, int iFixedIconWidth /* = -1 */ ) 100 { 101 if( text ) 102 { 103 if( bDoAlloc ) 104 { 105 int iRetVal; 106 107 char* szText = new char[ strlen( text ) + 51 ]; // 50 extra chars added for line breaks later. 108 strcpy( szText, text ); 109 110 int iWidthMax, iHeight; 111 // Stupid usage of globals for font stuff... <grumble> 112 if( TextFlags == TPF_TYPE ) 113 { 114 void* pFontBefore = Set_Font( TypeFontPtr ); 115 DWORD FontXSpacingBefore = FontXSpacing; 116 FontXSpacing = -2; 117 118 int iWidthToClipAt = IsScrollActive ? Width : Width - UpGadget.Width; 119 // This call will place '\r's in the string where line breaks should occur. 120 Format_Window_String_New( text, iWidthToClipAt, iWidthMax, iHeight, szText, 50 ); 121 122 Set_Font( pFontBefore ); 123 FontXSpacing = FontXSpacingBefore; // Just in case it matters... Doubt it. 124 } 125 else 126 { 127 // Currently never called. Test well if you use IconList with a font other than TPF_TYPE, 128 // as the character spacing globals get set weirdly, I've found. 129 int iWidthToClipAt = IsScrollActive ? Width : Width - UpGadget.Width; 130 // This call will place '\r's in the string where line breaks should occur. 131 Format_Window_String_New( text, iWidthToClipAt, iWidthMax, iHeight, szText, 50 ); 132 } 133 134 // Each break character causes a line to be added to list. 135 char szBreakchars[] = "\r\n\v\f"; 136 char* szToken; 137 char* szNextChar = szText; 138 szToken = strtok( szText, szBreakchars ); 139 while( szToken ) 140 { 141 while( szNextChar < szToken ) 142 { 143 // We expected szToken to begin at szNextChar. Since it doesn't, extra break 144 // characters must have been removed by strtok as they were adjacent. We want 145 // a line break for every break character, so add lines for each space that 146 // szNextChar is off by. 147 szNextChar++; 148 Add_Item_Detail( " ", szHelp, pIcon0, IconKind0, szExtraDataString, pvExtraDataPtr, pColorRemap, pIcon1, IconKind1, pIcon2, IconKind2, pFixedIcon, FixedIconKind, iXFixedIcon, iYFixedIcon, iFixedIconWidth ); 149 } 150 iRetVal = Add_Item_Detail( szToken, szHelp, pIcon0, IconKind0, szExtraDataString, pvExtraDataPtr, pColorRemap, pIcon1, IconKind1, pIcon2, IconKind2, pFixedIcon, FixedIconKind, iXFixedIcon, iYFixedIcon, iFixedIconWidth ); 151 152 // Expect next token two chars after the end of this one. 153 szNextChar = szToken + strlen( szToken ) + 1; 154 155 // Get next token. 156 szToken = strtok( NULL, szBreakchars ); 157 } 158 delete [] szText; 159 return iRetVal; // Last value returned by ListClass::Add_Item 160 } 161 else 162 { 163 // Add one item to list. 164 IconList_ItemExtras* pItemExtra = new IconList_ItemExtras; 165 pItemExtra->bMultiSelected = false; 166 pItemExtra->pIcon[0] = pIcon0; 167 pItemExtra->IconKind[0] = IconKind0; 168 pItemExtra->pIcon[1] = pIcon1; 169 pItemExtra->IconKind[1] = IconKind1; 170 pItemExtra->pIcon[2] = pIcon2; 171 pItemExtra->IconKind[2] = IconKind2; 172 pItemExtra->FixedIcon.pIcon = pFixedIcon; 173 pItemExtra->FixedIcon.IconKind = FixedIconKind; 174 pItemExtra->FixedIcon.xOffset = iXFixedIcon; 175 pItemExtra->FixedIcon.yOffset = iYFixedIcon; 176 pItemExtra->FixedIcon.iWidth = iFixedIconWidth; 177 pItemExtra->pvExtraData = pvExtraDataPtr; 178 pItemExtra->pColorRemap = pColorRemap; 179 if( szHelp ) 180 { 181 // Copy help into new help string. 182 pItemExtra->szHelp = new char[ strlen( szHelp ) + 1 ]; 183 strcpy( pItemExtra->szHelp, szHelp ); 184 } 185 if( szExtraDataString ) 186 { 187 // Copy special data string into new extradata string. 188 pItemExtra->szExtraData = new char[ strlen( szExtraDataString ) + 1 ]; 189 strcpy( pItemExtra->szExtraData, szExtraDataString ); 190 } 191 ExtrasList.Add( pItemExtra ); 192 193 return ListClass::Add_Item( text ); 194 } 195 } 196 else 197 { 198 // (no text for new item) 199 if( pIcon0 || pIcon1 || pIcon2 ) 200 { 201 // Note: Cannot add an entry without text unless string allocation is being handled by me. 202 // Otherwise, because we want the icon to show up, create a blank entry for the ListClass. 203 if( bDoAlloc ) 204 { 205 IconList_ItemExtras* pItemExtra = new IconList_ItemExtras; 206 pItemExtra->bMultiSelected = false; 207 pItemExtra->pIcon[0] = pIcon0; 208 pItemExtra->IconKind[0] = IconKind0; 209 pItemExtra->pIcon[1] = pIcon1; 210 pItemExtra->IconKind[1] = IconKind1; 211 pItemExtra->pIcon[2] = pIcon2; 212 pItemExtra->IconKind[2] = IconKind2; 213 pItemExtra->FixedIcon.pIcon = pFixedIcon; 214 pItemExtra->FixedIcon.IconKind = FixedIconKind; 215 pItemExtra->FixedIcon.xOffset = iXFixedIcon; 216 pItemExtra->FixedIcon.yOffset = iYFixedIcon; 217 pItemExtra->FixedIcon.iWidth = iFixedIconWidth; 218 pItemExtra->pvExtraData = pvExtraDataPtr; 219 pItemExtra->pColorRemap = pColorRemap; 220 if( szHelp ) 221 { 222 // Copy help into new help string. 223 pItemExtra->szHelp = new char[ strlen( szHelp ) + 1 ]; 224 strcpy( pItemExtra->szHelp, szHelp ); 225 } 226 if( szExtraDataString ) 227 { 228 // Copy special data string into new extradata string. 229 pItemExtra->szExtraData = new char[ strlen( szExtraDataString ) + 1 ]; 230 strcpy( pItemExtra->szExtraData, szExtraDataString ); 231 } 232 ExtrasList.Add( pItemExtra ); 233 234 if( iMaxItems && List.Count() == iMaxItems ) 235 { 236 // Delete head of list. 237 Remove_Item( 0 ); 238 } 239 // Create new string, essentially blank. 240 char* szText = new char[2]; 241 strcpy( szText, " " ); 242 return ListClass::Add_Item( szText ); 243 } 244 else 245 // Cannot add entry, as text is blank and ListClass::Add_Item will do nothing. 246 // The Icon we want will not show up. 247 return List.Count() - 1; 248 } 249 else 250 return ListClass::Add_Item( text ); 251 } 252 } 253 254 //*********************************************************************************************** 255 int IconListClass::Add_Item_Detail( const char* szToken, const char* szHelp, 256 void* pIcon0, ICONKIND IconKind0, const char* szExtraDataString, 257 void* pvExtraData, RemapControlType* pColorRemap, 258 void* pIcon1, ICONKIND IconKind1, 259 void* pIcon2, ICONKIND IconKind2, 260 void* pFixedIcon, ICONKIND FixedIconKind, int iXFixedIcon, int iYFixedIcon, int iFixedIconWidth ) 261 { 262 // Broken out of above function as it is repeated. 263 264 // Add one item to list. 265 // Too many entries? 266 if( iMaxItems && List.Count() == iMaxItems ) 267 { 268 // Delete head of list. 269 Remove_Item( 0 ); 270 } 271 // Create icon entry. 272 IconList_ItemExtras* pItemExtra = new IconList_ItemExtras; 273 pItemExtra->bMultiSelected = false; 274 pItemExtra->pIcon[0] = pIcon0; // ajw - Question: repeat the icon for each entry? make it optional? 275 pItemExtra->IconKind[0] = IconKind0; 276 pItemExtra->pIcon[1] = pIcon1; 277 pItemExtra->IconKind[1] = IconKind1; 278 pItemExtra->pIcon[2] = pIcon2; 279 pItemExtra->IconKind[2] = IconKind2; 280 pItemExtra->FixedIcon.pIcon = pFixedIcon; 281 pItemExtra->FixedIcon.IconKind = FixedIconKind; 282 pItemExtra->FixedIcon.xOffset = iXFixedIcon; 283 pItemExtra->FixedIcon.yOffset = iYFixedIcon; 284 pItemExtra->FixedIcon.iWidth = iFixedIconWidth; 285 pItemExtra->pvExtraData = pvExtraData; 286 pItemExtra->pColorRemap = pColorRemap; 287 if( szHelp ) 288 { 289 // Copy help into new help string. 290 pItemExtra->szHelp = new char[ strlen( szHelp ) + 1 ]; 291 strcpy( pItemExtra->szHelp, szHelp ); 292 } 293 if( szExtraDataString ) 294 { 295 // Copy special data string into new extradata string. 296 pItemExtra->szExtraData = new char[ strlen( szExtraDataString ) + 1 ]; 297 strcpy( pItemExtra->szExtraData, szExtraDataString ); 298 } 299 ExtrasList.Add( pItemExtra ); 300 // Create text entry. 301 // Copy text to new string. 302 char* szTextBit = new char[ strlen( szToken ) + 1 ]; 303 strcpy( szTextBit, szToken ); 304 return ListClass::Add_Item( szTextBit ); 305 } 306 307 //*********************************************************************************************** 308 int IconListClass::Add_Item( int text ) 309 { 310 return Add_Item( Text_String(text), NULL, NULL, ICON_SHAPE ); 311 } 312 313 //*********************************************************************************************** 314 int IconListClass::Add_Item( int text, const char* szHelp, 315 void* pIcon0, ICONKIND IconKind0, const char* szExtraDataString /* = NULL */, 316 void* pvExtraDataPtr /* = NULL */, RemapControlType* pColorRemap /* = NULL */, 317 void* pIcon1 /* = NULL */, ICONKIND IconKind1 /* = ICON_SHAPE */, 318 void* pIcon2 /* = NULL */, ICONKIND IconKind2 /* = ICON_SHAPE */, 319 void* pFixedIcon /* = NULL */, ICONKIND FixedIconKind /* = ICON_SHAPE */, int iXFixedIcon /* = 0 */, int iYFixedIcon /* = 0 */, int iFixedIconWidth /* = -1 */ ) 320 { 321 return Add_Item( Text_String(text), szHelp, pIcon0, IconKind0, szExtraDataString, pvExtraDataPtr, pColorRemap, 322 pIcon1, IconKind1, pIcon2, IconKind2, pFixedIcon, FixedIconKind, iXFixedIcon, iYFixedIcon, iFixedIconWidth ); 323 } 324 325 //*********************************************************************************************** 326 void IconListClass::Remove_Item( char const * text ) 327 { 328 if( text ) 329 Remove_Item( List.ID(text) ); 330 } 331 332 //*********************************************************************************************** 333 void IconListClass::Remove_Item( int index ) 334 { 335 if( (unsigned)index < List.Count() ) 336 { 337 delete (IconList_ItemExtras*)ExtrasList[ index ]; 338 ExtrasList.Delete( index ); 339 if( bDoAlloc ) 340 // Delete alloc'ed string. 341 delete [] (char*)List[index]; 342 ListClass::Remove_Item( index ); 343 344 // I should probably put this in ListClass:Remove_Item(), as it seems clearly to be 345 // missing, but I want to only affect my own new code, to not introduce possible bugs. 346 // Shift the selected index if appropriate... 347 if( SelectedIndex >= index ) 348 { 349 SelectedIndex--; 350 if( SelectedIndex < 0 ) 351 SelectedIndex = 0; 352 } 353 } 354 } 355 356 /*********************************************************************************************** 357 * IconListClass::Draw_Entry -- Calls ListClass::Draw_Entry, then adds icon. * 358 * * 359 * This routine is called by the Draw_Me function when it desired to redraw a particular * 360 * text line in the list box. * 361 * * 362 * INPUT: index -- The index of the list entry to draw. This index is based on the * 363 * total list and NOT the current visible view page. * 364 * * 365 * x,y -- Pixel coordinates for the upper left corner of the text entry. * 366 * * 367 * width -- The maximum width that the text may draw over. It is expected that * 368 * this drawing routine entirely fills this length. * 369 * * 370 * selected -- bool; Is this a selected (highlighted) listbox entry? * 371 * * 372 * OUTPUT: none * 373 * WARNINGS: none * 374 * HISTORY: * 375 * 07/07/1998 ajw: Created. * 376 *=============================================================================================*/ 377 378 #define PREICONGAP 1 379 #define ICONTEXTGAP 2 380 381 void IconListClass::Draw_Entry( int index, int x, int y, int width, int selected ) 382 { 383 IconList_ItemExtras* pExtras = (IconList_ItemExtras*)ExtrasList[ index ]; 384 385 int xText = x; 386 // ajw If I end up needing to use SHAPEs for icons, figure out shape width here and offset x. 387 bool bIconsPresent = false; 388 for( int iIcon = 0; iIcon != 3; iIcon++ ) 389 if( pExtras->pIcon[ iIcon ] && pExtras->IconKind[ iIcon ] == ICON_DIB ) 390 { 391 // Push text over to accommodate icon. 392 int iWidthIcon = PREICONGAP + DIBWidth( (char*)pExtras->pIcon[ iIcon ] ); 393 xText += iWidthIcon; 394 width -= iWidthIcon; 395 bIconsPresent = true; 396 } 397 if( bIconsPresent ) 398 { 399 xText += ICONTEXTGAP; 400 width -= ICONTEXTGAP; 401 } 402 403 RemapControlType* pRemap = pExtras->pColorRemap; 404 if( !pRemap ) 405 { 406 // Tabs hack. If there are icons, and a tab, push back the FIRST tab appropriately. 407 // (Ignore others. This is a hack because having more than one tab will now break this.) 408 // See local version of this same hack, below. 409 int TempTabs; 410 const int* TabsSave; 411 if( Tabs ) 412 { 413 TempTabs = *Tabs - ( xText - x ); 414 TabsSave = Tabs; 415 Tabs = &TempTabs; 416 } 417 switch( iSelectType ) 418 { 419 case 0: 420 // Don't draw any items selected (even if they are, really, in ListClass). 421 ListClass::Draw_Entry( index, xText, y, width, false ); 422 break; 423 case 1: 424 ListClass::Draw_Entry( index, xText, y, width, selected ); 425 break; 426 case 2: 427 // Ignore 'selected' parameter. We use our own records. 428 ListClass::Draw_Entry( index, xText, y, width, pExtras->bMultiSelected ); 429 break; 430 } 431 // Restore Tabs. 432 if( Tabs ) 433 Tabs = TabsSave; 434 } 435 else 436 { 437 // Use different color remapping. 438 // This is largely copied straight from ListClass::Draw_Entry()... 439 440 TextPrintType flags = TextFlags; 441 442 bool bShowSelected; 443 444 switch( iSelectType ) 445 { 446 case 0: 447 bShowSelected = false; 448 break; 449 case 1: 450 bShowSelected = selected; 451 break; 452 case 2: 453 bShowSelected = pExtras->bMultiSelected; 454 break; 455 } 456 457 if( bShowSelected ) 458 { 459 flags = flags | TPF_BRIGHT_COLOR; 460 LogicPage->Fill_Rect( xText, y, xText + width - 1, y + LineHeight - 1, pRemap->Shadow ); 461 } 462 else 463 { 464 if (!(flags & TPF_USE_GRAD_PAL)) 465 { 466 flags = flags | TPF_MEDIUM_COLOR; 467 } 468 } 469 // Tabs hack. If there are icons, and a tab, push back the FIRST tab appropriately. 470 // (Ignore others. This is a hack because having more than one tab will now break this.) 471 if( Tabs ) 472 { 473 int tab = *Tabs - ( xText - x ); 474 Conquer_Clip_Text_Print( List[index], xText, y, pRemap, TBLACK, flags, width, &tab ); 475 } 476 else 477 Conquer_Clip_Text_Print( List[index], xText, y, pRemap, TBLACK, flags, width, NULL ); 478 } 479 480 // Draw fixed position icon. 481 if( pExtras->FixedIcon.pIcon ) 482 { 483 if( pExtras->FixedIcon.IconKind == ICON_SHAPE ) 484 CC_Draw_Shape( pExtras->FixedIcon.pIcon, 0, x + pExtras->FixedIcon.xOffset, y + pExtras->FixedIcon.yOffset, WINDOW_MAIN, SHAPE_NORMAL ); 485 // Put similar code in here for shapes if used... 486 else 487 CC_Draw_DIB( (char*)pExtras->FixedIcon.pIcon, x + pExtras->FixedIcon.xOffset, y + pExtras->FixedIcon.yOffset, pExtras->FixedIcon.iWidth, WINDOW_MAIN ); 488 } 489 490 // Draw variable position left-of-text icons. 491 for( iIcon = 0; iIcon != 3; iIcon++ ) 492 { 493 if( pExtras->pIcon[ iIcon ] ) 494 { 495 x += PREICONGAP; 496 if( pExtras->IconKind[ iIcon ] == ICON_SHAPE ) 497 CC_Draw_Shape( pExtras->pIcon[ iIcon ], 0, x, y, WINDOW_MAIN, SHAPE_NORMAL ); 498 // Put similar code in here for shapes if used... 499 else 500 { 501 CC_Draw_DIB( (char*)pExtras->pIcon[ iIcon ], x, y, 9999, WINDOW_MAIN ); 502 x += DIBWidth( (char*)pExtras->pIcon[ iIcon ] ); 503 } 504 } 505 } 506 } 507 508 //*********************************************************************************************** 509 int IconListClass::Action(unsigned flags, KeyNumType & key) 510 { 511 // Overriding of function is for the sake of MultiSelecting only. 512 if( iSelectType == 2 ) 513 { 514 if( !( flags & LEFTRELEASE ) ) 515 { 516 if( !( flags & KEYBOARD ) ) 517 { 518 int index = Get_Mouse_Y() - (Y+1); 519 index = index / LineHeight; 520 int iSelected = CurrentTopIndex + index; 521 iSelected = min( iSelected, List.Count() - 1 ); 522 if( iSelected >= 0 ) 523 ((IconList_ItemExtras*)ExtrasList[ iSelected ])->bMultiSelected = 524 !((IconList_ItemExtras*)ExtrasList[ iSelected ])->bMultiSelected; 525 } 526 } 527 } 528 return ListClass::Action( flags, key ); 529 } 530 531 //*********************************************************************************************** 532 // * IconListClass::Show_Last_Item -- Scrolls listbox down to ensure that last entry is visible. 533 // ajw 07/09/98 534 void IconListClass::Show_Last_Item() 535 { 536 int iItemLast = List.Count() - 1; 537 if( iItemLast - LineCount + 1 != CurrentTopIndex ) 538 { 539 Flag_To_Redraw(); 540 Set_View_Index( iItemLast - LineCount + 1 ); 541 } 542 } 543 544 //*********************************************************************************************** 545 bool IconListClass::bItemIsMultiSelected( int index ) const 546 { 547 if( index < ExtrasList.Count() && index > -1 ) 548 return ( (IconList_ItemExtras*)ExtrasList[ index ] )->bMultiSelected; 549 else 550 return false; 551 } 552 553 //*********************************************************************************************** 554 void IconListClass::MultiSelect( int index, bool bSelect ) 555 { 556 if( index < ExtrasList.Count() && index > -1 ) 557 ( (IconList_ItemExtras*)ExtrasList[ index ] )->bMultiSelected = bSelect; 558 } 559 560 //*********************************************************************************************** 561 const char* IconListClass::Get_Item_ExtraDataString( int index ) const 562 { 563 // Returns const pointer to the hidden "extra data" string that can be associated with each item. 564 // This is NULL if no extra data was assigned. 565 if( index < ExtrasList.Count() && index > -1 ) 566 { 567 return ( (IconList_ItemExtras*)ExtrasList[ index ] )->szExtraData; 568 } 569 return NULL; 570 } 571 572 //*********************************************************************************************** 573 void IconListClass::Set_Item_ExtraDataString( int index, const char* szNewString ) 574 { 575 if( index < ExtrasList.Count() && index > -1 ) 576 { 577 IconList_ItemExtras* pItemExtra = (IconList_ItemExtras*)ExtrasList[ index ]; 578 if( pItemExtra->szExtraData ) 579 { 580 // Delete the existing string. 581 delete [] pItemExtra->szExtraData; 582 } 583 if( szNewString ) 584 { 585 // Copy special data string into new extradata string. 586 pItemExtra->szExtraData = new char[ strlen( szNewString ) + 1 ]; 587 strcpy( pItemExtra->szExtraData, szNewString ); 588 } 589 else 590 pItemExtra->szExtraData = NULL; 591 } 592 } 593 594 //*********************************************************************************************** 595 void* IconListClass::Get_Item_ExtraDataPtr( int index ) const 596 { 597 // Returns the hidden "extra data" void pointer that can be associated with each item. 598 // This is NULL if no value was assigned. 599 if( index < ExtrasList.Count() && index > -1 ) 600 return ( (IconList_ItemExtras*)ExtrasList[ index ] )->pvExtraData; 601 else 602 return NULL; 603 } 604 605 //*********************************************************************************************** 606 void IconListClass::Set_Item_ExtraDataPtr( int index, void* pNewValue ) 607 { 608 // Sets the hidden "extra data" void pointer that can be associated with each item. 609 if( index < ExtrasList.Count() && index > -1 ) 610 ( (IconList_ItemExtras*)ExtrasList[ index ] )->pvExtraData = pNewValue; 611 } 612 613 //*********************************************************************************************** 614 const IconList_ItemExtras* IconListClass::Get_ItemExtras( int index ) const 615 { 616 if( index < ExtrasList.Count() && index > -1 ) 617 return (IconList_ItemExtras*)ExtrasList[ index ]; 618 else 619 return NULL; 620 } 621 622 //*********************************************************************************************** 623 const char* IconListClass::Get_Item_Help( int index ) const 624 { 625 // Returns pointer to the string allocated for tooltip help. 626 if( index < ExtrasList.Count() && index > -1 ) 627 return ( (IconList_ItemExtras*)ExtrasList[ index ] )->szHelp; 628 else 629 return NULL; 630 } 631 632 //*********************************************************************************************** 633 void IconListClass::Clear() 634 { 635 // Removes all items from list. 636 637 // Delete the IconList_ItemExtras structs created to hold extra info on each item. 638 for( int i = 0; i < ExtrasList.Count(); i++ ) 639 delete (IconList_ItemExtras*)ExtrasList[ i ]; 640 ExtrasList.Clear(); 641 642 if( bDoAlloc ) 643 { 644 // Delete all alloc'ed strings. 645 for( int i = 0; i < List.Count(); i++ ) 646 delete [] (char*)List[i]; 647 } 648 649 List.Clear(); 650 Remove_Scroll_Bar(); 651 CurrentTopIndex = 0; 652 } 653 654 //*********************************************************************************************** 655 RemapControlType* IconListClass::Get_Item_Color( int index ) 656 { 657 if( index < ExtrasList.Count() && index > -1 ) 658 return ( (IconList_ItemExtras*)ExtrasList[ index ] )->pColorRemap; 659 else 660 return NULL; 661 } 662 663 //*********************************************************************************************** 664 void IconListClass::Set_Item_Color( int index, RemapControlType* pColorRemap ) 665 { 666 if( index < ExtrasList.Count() && index > -1 ) 667 ( (IconList_ItemExtras*)ExtrasList[ index ] )->pColorRemap = pColorRemap; 668 } 669 670 //*********************************************************************************************** 671 int IconListClass::Find( const char* szItemToFind ) 672 { 673 // Returns -1 if szItemToFind is not found as the text BEGINNING one of the list entries, else index of item. 674 // Compare is case-sensitive. 675 for( int i = 0; i < List.Count(); i++ ) 676 { 677 if( strncmp( List[ i ], szItemToFind, strlen( szItemToFind ) ) == 0 ) 678 return i; 679 } 680 return -1; 681 } 682 683 //*********************************************************************************************** 684 int IconListClass::FindColor( RemapControlType* pColorRemap ) 685 { 686 // Returns -1 if no items of specified color are found, else first index. Assumes colorptr == colorptr is a valid equality test. 687 for( int i = 0; i < List.Count(); i++ ) 688 { 689 if( Get_Item_Color( i ) == pColorRemap ) 690 return i; 691 } 692 return -1; 693 } 694 695 //*********************************************************************************************** 696 bool IconListClass::Set_Item( unsigned int index, const char* szText ) 697 { 698 // Resets the text string allocated for an item. 699 if( !bDoAlloc || index >= List.Count() ) 700 return false; 701 702 // Delete alloc'ed string. 703 delete [] (char*)List[ index ]; 704 705 // Copy text to new string. 706 char* szTextNew = new char[ strlen( szText ) + 1 ]; 707 strcpy( szTextNew, szText ); 708 709 // Reassign List's ptr. 710 List[ index ] = szTextNew; 711 712 return true; 713 } 714 715 //*********************************************************************************************** 716 bool IconListClass::Set_Icon( unsigned int index, unsigned int iIconNumber, void* pIcon, ICONKIND IconKind ) 717 { 718 if( index >= List.Count() ) 719 return false; 720 721 // Sets one of the left-aligned icons. 722 ( (IconList_ItemExtras*)ExtrasList[ index ] )->pIcon[ iIconNumber ] = pIcon; 723 ( (IconList_ItemExtras*)ExtrasList[ index ] )->IconKind[ iIconNumber ] = IconKind; 724 return true; 725 } 726 727 //*********************************************************************************************** 728 int IconListClass::GetRealWidth() // sigh 729 { 730 if( IsScrollActive ) 731 return Width + ScrollGadget.Width; 732 return Width; 733 } 734 735 //*********************************************************************************************** 736 void IconListClass::Resize( int x, int y, int w, int h ) 737 { 738 Remove_Scroll_Bar(); // If there is one. 739 740 X = x; 741 Y = y; 742 Width = w; 743 Height = h; 744 745 Set_Position( x, y ); 746 747 LineCount = (h-1) / LineHeight; 748 749 750 if (List.Count() > LineCount) { 751 Add_Scroll_Bar(); 752 } 753 754 Flag_To_Redraw(); 755 } 756 757 //*********************************************************************************************** 758 int IconListClass::IndexUnderMouse() 759 { 760 // Returns index of line that mouse is currently over, or -1 for mouse not hitting valid index. 761 // Assumes that x position of mouse is already known to be over the iconlist. 762 int index = Get_Mouse_Y() - (Y+1); 763 index = index / LineHeight + CurrentTopIndex; 764 if( index > List.Count() - 1 || index < 0 ) 765 return -1; 766 return index; 767 } 768 769 //*********************************************************************************************** 770 int IconListClass::OffsetToIndex( int iIndex, int y ) 771 { 772 // Finds the current offset of item iIndex from the current top view index, in pixels, and add it to y. 773 return y + ( iIndex - CurrentTopIndex ) * LineHeight; 774 } 775 776 //*********************************************************************************************** 777 //*********************************************************************************************** 778 // * Format_Window_String_New 779 // Functions like Format_Window_String except it fixes an infinite loop bug that occurred when strings 780 // lacked suitable break points, eliminates the '@' as an escape character, and operates differently 781 // in that it leaves the original string along, writing results instead to a second string parameter, 782 // that is iExtraChars longer than the original string. This is all a big hack so that I can insert 783 // extra break characters when a break in a long single word has to be made. 784 // Hey - it's better than an infinite loop that forces you to reset your machine, as in the original code... 785 786 int Format_Window_String_New( const char* string, int maxlinelen, int& width, int& height, char* szReturn, int iExtraChars ) 787 { 788 int linelen; 789 int lines = 0; 790 width = 0; 791 height = 0; 792 793 // In no string was passed in, then there are no lines. 794 if (!string) return(0); 795 796 // While there are more letters left divide the line up. 797 while (*string) { 798 linelen = 0; 799 height += FontHeight + FontYSpacing; 800 lines++; 801 802 // While the current line is less then the max length... 803 *szReturn = *string; 804 linelen += Char_Pixel_Width( *string ); 805 while ( linelen < maxlinelen && *string != '\r' && *string != '\0' ) 806 { 807 *++szReturn = *++string; 808 linelen += Char_Pixel_Width( *string ); 809 } 810 811 // if the line is too long... 812 if (linelen >= maxlinelen) 813 { 814 /* 815 ** Back up to an appropriate location to break. 816 */ 817 const char* stringOverEnd = string; 818 while( linelen > 0 && *string != ' ' && *string != '\r' && *string != '\0' ) 819 { 820 linelen -= Char_Pixel_Width(*string--); 821 } 822 if( linelen <= 0 ) 823 { 824 // We could not find a nice break point. 825 // Go back one char from over-the-end point and add in a break there. 826 string = stringOverEnd - 1; 827 if( iExtraChars > 0 ) 828 iExtraChars--; // One less to make use of later. 829 else 830 // We've used up all our extras characters. 831 // Put in a break below by wiping out a valid char here. 832 szReturn--; 833 } 834 else 835 { 836 // Back up szReturn to same location. 837 szReturn -= ( stringOverEnd - string ); 838 } 839 } 840 841 /* 842 ** Record the largest width of the worst case string. 843 */ 844 if (linelen > width) { 845 width = linelen; 846 } 847 848 /* 849 ** Force a break at the end of the line. 850 */ 851 if (*string) { 852 *szReturn++ = '\r'; 853 string++; 854 } 855 } 856 return(lines); 857 } 858 859 //*********************************************************************************************** 860 void CC_Draw_DIB( const char* pDIB, int xDest, int yDest, int iWidth, WindowNumberType window ) 861 { 862 // A very basic DIB drawing routine. No clipping. No edge of window overrun checking. 863 // If iWidth is too large, default width of dib is used. 864 // If iWidth is negative, dib isn't drawn. 865 if( pDIB && iWidth >= 0 ) 866 { 867 868 int iWidthDIB = DIBWidth( pDIB ); 869 int iHeight = DIBHeight( pDIB ); 870 const char* pBits = FindDIBBits( pDIB ); 871 872 int iSrcPitch = ( iWidthDIB + 3 ) & ~3; 873 874 if( iWidth > iWidthDIB ) 875 iWidth = iWidthDIB; 876 877 GraphicViewPortClass draw_window( LogicPage->Get_Graphic_Buffer(), 878 WindowList[window][WINDOWX] + LogicPage->Get_XPos(), 879 WindowList[window][WINDOWY] + LogicPage->Get_YPos(), 880 WindowList[window][WINDOWWIDTH], 881 WindowList[window][WINDOWHEIGHT] ); 882 if( draw_window.Lock() ) 883 { 884 int iDestPitch = draw_window.Get_Pitch() + draw_window.Get_Width(); // Meaning of "Pitch" in this class seems to mean the eol skip. 885 char* pLineDest = (char*)draw_window.Get_Offset() + xDest + ( yDest + iHeight - 1 ) * iDestPitch; 886 887 const char* pLineSrc = pBits; 888 for( int y = 0; y != iHeight; y++ ) 889 { 890 char* pDest = pLineDest; 891 const char* pSrc = pLineSrc; 892 for( int x = 0; x != iWidth; x++ ) 893 { 894 *pDest++ = *pSrc++; 895 } 896 pLineDest -= iDestPitch; 897 pLineSrc += iSrcPitch; 898 } 899 draw_window.Unlock(); 900 } 901 } 902 // else 903 // debugprint( "CC_Draw_DIB bad case ------------ pDib %i, iWidth %i\n", pDIB, iWidth ); 904 } 905 906 907 #endif