Changeset 3585 for trunk/src/comctl32/tab.cpp
- Timestamp:
- May 22, 2000, 7:25:13 PM (25 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/comctl32/tab.cpp
r3369 r3585 1 /* $Id: tab.cpp,v 1. 3 2000-04-12 16:38:59cbratschi Exp $ */1 /* $Id: tab.cpp,v 1.4 2000-05-22 17:25:11 cbratschi Exp $ */ 2 2 /* 3 3 * Tab control … … 12 12 * Image list support 13 13 * Multiline support 14 * Unicode support15 14 */ 16 15 17 16 /* inconsistent: report! */ 18 17 /* 19 - Corel WINE 20000 317level18 - Corel WINE 20000513 level 20 19 - (WINE 991212 level) 21 20 */ … … 49 48 50 49 /****************************************************************************** 50 * Hot-tracking timer constants 51 */ 52 #define TAB_HOTTRACK_TIMER 1 53 #define TAB_HOTTRACK_TIMER_INTERVAL 100 /* milliseconds */ 54 55 /****************************************************************************** 51 56 * Prototypes 52 57 */ … … 54 59 static void TAB_InvalidateTabArea(HWND hwnd, TAB_INFO* infoPtr); 55 60 static void TAB_EnsureSelectionVisible(HWND hwnd, TAB_INFO* infoPtr); 61 static void TAB_DrawItem(HWND hwnd, HDC hdc, INT iItem); 62 static void TAB_DrawItemInterior(HWND hwnd, HDC hdc, INT iItem, RECT* drawRect); 56 63 57 64 static VOID … … 123 130 if ((iItem < 0) || (iItem >= infoPtr->uNumItem)) return 0; 124 131 125 infoPtr->uFocus=iItem; 126 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BUTTONS) { 127 // FIXME (tab,"Should set input focus\n"); 128 } else { 129 if (infoPtr->iSelected != iItem) { 130 if (sendNotify(hwnd,TCN_SELCHANGING) != TRUE) { 132 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BUTTONS) 133 { 134 //FIXME (tab,"Should set input focus\n"); 135 } else 136 { 137 if (infoPtr->iSelected != iItem || infoPtr->uFocus == -1) 138 { 139 infoPtr->uFocus = iItem; 140 if (sendNotify(hwnd,TCN_SELCHANGING) != TRUE) 141 { 131 142 infoPtr->iSelected = iItem; 132 143 sendNotify(hwnd,TCN_SELCHANGE); … … 166 177 RECT* selectedRect) 167 178 { 168 RECT tmpItemRect; 179 RECT tmpItemRect,clientRect; 180 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); 169 181 170 182 /* 171 183 * Perform a sanity check and a trivial visibility check. 172 184 */ 173 if ( (infoPtr->uNumItem == 0) ||185 if ( (infoPtr->uNumItem <= 0) || 174 186 (itemIndex >= infoPtr->uNumItem) || 175 ( itemIndex < infoPtr->leftmostVisible) )187 (!(lStyle &TCS_MULTILINE) && (itemIndex < infoPtr->leftmostVisible)) ) 176 188 return FALSE; 177 189 … … 187 199 */ 188 200 *itemRect = infoPtr->items[itemIndex].rect; 201 202 /* 203 * calculate the times bottom and top based on the row 204 */ 205 GetClientRect(hwnd, &clientRect); 206 207 if (lStyle & TCS_BOTTOM) 208 { 209 itemRect->bottom = clientRect.bottom - 210 SELECTED_TAB_OFFSET - 211 itemRect->top * (infoPtr->tabHeight - 2); 212 213 itemRect->top = clientRect.bottom - 214 infoPtr->tabHeight - 215 itemRect->top * ( infoPtr->tabHeight - 2); 216 } 217 else 218 { 219 itemRect->bottom = clientRect.top + 220 infoPtr->tabHeight + 221 itemRect->top * (infoPtr->tabHeight - 2); 222 itemRect->top = clientRect.top + 223 SELECTED_TAB_OFFSET+ 224 itemRect->top * (infoPtr->tabHeight - 2); 225 } 189 226 190 227 /* … … 409 446 TAB_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam) 410 447 { 448 sendNotify(hwnd,NM_CLICK); 449 450 return 0; 451 } 452 453 static LRESULT 454 TAB_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam) 455 { 456 sendNotify(hwnd,NM_RCLICK); 457 458 return 0; 459 } 460 461 /****************************************************************************** 462 * TAB_DrawLoneItemInterior 463 * 464 * This calls TAB_DrawItemInterior. However, TAB_DrawItemInterior is normally 465 * called by TAB_DrawItem which is normally called by TAB_Refresh which sets 466 * up the device context and font. This routine does the same setup but 467 * only calls TAB_DrawItemInterior for the single specified item. 468 */ 469 static void 470 TAB_DrawLoneItemInterior(HWND hwnd, TAB_INFO* infoPtr, int iItem) 471 { 472 HDC hdc = GetDC(hwnd); 473 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont); 474 TAB_DrawItemInterior(hwnd, hdc, iItem, NULL); 475 SelectObject(hdc, hOldFont); 476 ReleaseDC(hwnd, hdc); 477 } 478 479 /****************************************************************************** 480 * TAB_HotTrackTimerProc 481 * 482 * When a mouse-move event causes a tab to be highlighted (hot-tracking), a 483 * timer is setup so we can check if the mouse is moved out of our window. 484 * (We don't get an event when the mouse leaves, the mouse-move events just 485 * stop being delivered to our window and just start being delivered to 486 * another window.) This function is called when the timer triggers so 487 * we can check if the mouse has left our window. If so, we un-highlight 488 * the hot-tracked tab. 489 */ 490 static VOID CALLBACK 491 TAB_HotTrackTimerProc 492 ( 493 HWND hwnd, // handle of window for timer messages 494 UINT uMsg, // WM_TIMER message 495 UINT idEvent, // timer identifier 496 DWORD dwTime // current system time 497 ) 498 { 499 TAB_INFO* infoPtr = TAB_GetInfoPtr(hwnd); 500 501 if (infoPtr != NULL && infoPtr->iHotTracked >= 0) 502 { 503 POINT pt; 504 505 /* 506 ** If we can't get the cursor position, or if the cursor is outside our 507 ** window, we un-highlight the hot-tracked tab. Note that the cursor is 508 ** "outside" even if it is within our bounding rect if another window 509 ** overlaps. Note also that the case where the cursor stayed within our 510 ** window but has moved off the hot-tracked tab will be handled by the 511 ** WM_MOUSEMOVE event. 512 */ 513 if (!GetCursorPos(&pt) || WindowFromPoint(pt) != hwnd) 514 { 515 // Redraw iHotTracked to look normal 516 INT iRedraw = infoPtr->iHotTracked; 517 infoPtr->iHotTracked = -1; 518 TAB_DrawLoneItemInterior(hwnd, infoPtr, iRedraw); 519 520 // Kill this timer 521 KillTimer(hwnd, TAB_HOTTRACK_TIMER); 522 } 523 } 524 } 525 526 /****************************************************************************** 527 * TAB_RecalcHotTrack 528 * 529 * If a tab control has the TCS_HOTTRACK style, then the tab under the mouse 530 * should be highlighted. This function determines which tab in a tab control, 531 * if any, is under the mouse and records that information. The caller may 532 * supply output parameters to receive the item number of the tab item which 533 * was highlighted but isn't any longer and of the tab item which is now 534 * highlighted but wasn't previously. The caller can use this information to 535 * selectively redraw those tab items. 536 * 537 * If the caller has a mouse position, it can supply it through the pos 538 * parameter. For example, TAB_MouseMove does this. Otherwise, the caller 539 * supplies NULL and this function determines the current mouse position 540 * itself. 541 */ 542 static void 543 TAB_RecalcHotTrack 544 ( 545 HWND hwnd, 546 const LPARAM* pos, 547 int* out_redrawLeave, 548 int* out_redrawEnter 549 ) 550 { 551 TAB_INFO* infoPtr = TAB_GetInfoPtr(hwnd); 552 553 int item = -1; 554 555 556 if (out_redrawLeave != NULL) 557 *out_redrawLeave = -1; 558 if (out_redrawEnter != NULL) 559 *out_redrawEnter = -1; 560 561 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_HOTTRACK) 562 { 563 POINT pt; 564 UINT flags; 565 566 if (pos == NULL) 567 { 568 GetCursorPos(&pt); 569 ScreenToClient(hwnd, &pt); 570 } 571 else 572 { 573 pt.x = LOWORD(*pos); 574 pt.y = HIWORD(*pos); 575 } 576 577 item = TAB_InternalHitTest(hwnd, infoPtr, pt, &flags); 578 } 579 580 if (item != infoPtr->iHotTracked) 581 { 582 if (infoPtr->iHotTracked >= 0) 583 { 584 // Mark currently hot-tracked to be redrawn to look normal 585 if (out_redrawLeave != NULL) 586 *out_redrawLeave = infoPtr->iHotTracked; 587 588 if (item < 0) 589 { 590 // Kill timer which forces recheck of mouse pos 591 KillTimer(hwnd, TAB_HOTTRACK_TIMER); 592 } 593 } 594 else 595 { 596 // Start timer so we recheck mouse pos 597 UINT timerID = SetTimer 598 ( 599 hwnd, 600 TAB_HOTTRACK_TIMER, 601 TAB_HOTTRACK_TIMER_INTERVAL, 602 TAB_HotTrackTimerProc 603 ); 604 605 if (timerID == 0) 606 return; /* Hot tracking not available */ 607 } 608 609 infoPtr->iHotTracked = item; 610 611 if (item >= 0) 612 { 613 // Mark new hot-tracked to be redrawn to look highlighted 614 if (out_redrawEnter != NULL) 615 *out_redrawEnter = item; 616 } 617 } 618 } 619 620 /****************************************************************************** 621 * TAB_MouseMove 622 * 623 * Handles the mouse-move event. Updates tooltips. Updates hot-tracking. 624 */ 625 static LRESULT 626 TAB_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam) 627 { 628 int redrawLeave; 629 int redrawEnter; 630 411 631 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd); 412 POINT pt;413 INT newItem;414 UINT dummy;415 632 416 633 if (infoPtr->hwndToolTip) … … 418 635 WM_LBUTTONDOWN, wParam, lParam); 419 636 420 pt.x = (INT)LOWORD(lParam); 421 pt.y = (INT)HIWORD(lParam); 422 423 newItem=TAB_InternalHitTest (hwnd, infoPtr,pt,&dummy); 424 425 // TRACE(tab, "On Tab, item %d\n", newItem); 426 427 if ( (newItem!=-1) && 428 (infoPtr->iSelected != newItem) ) 429 { 430 if (sendNotify(hwnd,TCN_SELCHANGING) != TRUE) 431 { 432 infoPtr->iSelected = newItem; 433 infoPtr->uFocus = newItem; 434 sendNotify(hwnd,TCN_SELCHANGE); 435 436 TAB_EnsureSelectionVisible(hwnd, infoPtr); 437 438 TAB_InvalidateTabArea(hwnd, infoPtr); 439 } 440 } 441 sendNotify(hwnd,NM_CLICK); 442 443 return 0; 444 } 445 446 static LRESULT 447 TAB_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam) 448 { 449 sendNotify(hwnd,NM_RCLICK); 450 451 return 0; 452 } 453 454 static LRESULT 455 TAB_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam) 456 { 457 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd); 458 459 if (infoPtr->hwndToolTip) 460 TAB_RelayEvent (infoPtr->hwndToolTip, hwnd, 461 WM_LBUTTONDOWN, wParam, lParam); 637 /* Determine which tab to highlight. Redraw tabs which change highlight 638 ** status. */ 639 TAB_RecalcHotTrack(hwnd, &lParam, &redrawLeave, &redrawEnter); 640 641 if (redrawLeave != -1) 642 TAB_DrawLoneItemInterior(hwnd, infoPtr, redrawLeave); 643 if (redrawEnter != -1) 644 TAB_DrawLoneItemInterior(hwnd, infoPtr, redrawEnter); 645 462 646 return 0; 463 647 } … … 486 670 */ 487 671 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM) 488 prc->bottom += infoPtr->tabHeight;672 prc->bottom += (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2; 489 673 else 490 prc->top -= infoPtr->tabHeight;674 prc->top -= (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2; 491 675 492 676 /* … … 520 704 */ 521 705 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM) 522 prc->bottom -= infoPtr->tabHeight;706 prc->bottom -= (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2; 523 707 else 524 prc->top += infoPtr->tabHeight;708 prc->top += (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2; 525 709 526 710 } … … 543 727 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd); 544 728 545 if (nScrollCode == SB_LINELEFT) 546 { 547 if (infoPtr->leftmostVisible>0) 548 { 549 infoPtr->leftmostVisible--; 550 551 TAB_InvalidateTabArea(hwnd, infoPtr); 552 } 553 } 554 else if (nScrollCode == SB_LINERIGHT) 555 { 556 if (infoPtr->leftmostVisible< (infoPtr->uNumItem-1)) 557 { 558 infoPtr->leftmostVisible++; 559 560 TAB_InvalidateTabArea(hwnd, infoPtr); 561 } 562 } 563 564 return 0; 729 if(nScrollCode == SB_THUMBPOSITION && nPos != infoPtr->leftmostVisible) 730 { 731 if(nPos < infoPtr->leftmostVisible) 732 infoPtr->leftmostVisible--; 733 else 734 infoPtr->leftmostVisible++; 735 736 TAB_RecalcHotTrack(hwnd, NULL, NULL, NULL); 737 TAB_InvalidateTabArea(hwnd, infoPtr); 738 SendMessageA(infoPtr->hwndUpDown, UDM_SETPOS, 0, 739 MAKELONG(infoPtr->leftmostVisible, 0)); 740 } 741 742 return 0; 565 743 } 566 744 … … 576 754 const RECT* clientRect) 577 755 { 756 INT maxRange = 0; 757 578 758 if (infoPtr->needsScrolling) 579 759 { 580 760 RECT controlPos; 761 INT vsize, tabwidth; 581 762 582 763 /* … … 607 788 * control. 608 789 */ 609 infoPtr->hwndUpDown = CreateWindowA(" ScrollBar",610 611 WS_VISIBLE | WS_CHILD | WS_OVERLAPPED | SBS_HORZ,790 infoPtr->hwndUpDown = CreateWindowA("msctls_updown32", 791 "", 792 WS_VISIBLE | WS_CHILD | UDS_HORZ, 612 793 controlPos.left, controlPos.top, 613 794 controlPos.right - controlPos.left, … … 627 808 SWP_SHOWWINDOW | SWP_NOZORDER); 628 809 } 810 811 /* Now calculate upper limit of the updown control range. 812 * We do this by calculating how many tabs will be offscreen when the 813 * last tab is visible. 814 */ 815 if(infoPtr->uNumItem) 816 { 817 vsize = clientRect->right - (controlPos.right - controlPos.left + 1); 818 maxRange = infoPtr->uNumItem; 819 tabwidth = infoPtr->items[maxRange-1].rect.right; 820 821 for(; maxRange > 0; maxRange--) 822 { 823 if(tabwidth - infoPtr->items[maxRange - 1].rect.left > vsize) 824 break; 825 } 826 827 if(maxRange == infoPtr->uNumItem) 828 maxRange--; 829 } 629 830 } 630 831 else … … 638 839 } 639 840 } 841 842 if (infoPtr->hwndUpDown) 843 SendMessageA(infoPtr->hwndUpDown, UDM_SETRANGE32, 0, maxRange); 640 844 } 641 845 … … 657 861 INT curItem; 658 862 INT curItemLeftPos; 863 INT curItemRowCount; 659 864 HFONT hFont, hOldFont; 660 865 HDC hdc; … … 681 886 */ 682 887 curItemLeftPos = 0; 683 684 if (!((lStyle & TCS_FIXEDWIDTH) || (lStyle & TCS_OWNERDRAWFIXED))) 888 curItemRowCount = 0; 889 890 if (!(lStyle & TCS_FIXEDWIDTH) && !((lStyle & TCS_OWNERDRAWFIXED) && infoPtr->fSizeSet)) 685 891 { 686 892 int item_height; … … 717 923 { 718 924 /* 719 * Calculate the vertical position of the tab720 */721 if (lStyle & TCS_BOTTOM)722 {723 infoPtr->items[curItem].rect.bottom = clientRect.bottom -724 SELECTED_TAB_OFFSET;725 infoPtr->items[curItem].rect.top = clientRect.bottom -726 infoPtr->tabHeight;727 }728 else729 {730 infoPtr->items[curItem].rect.top = clientRect.top +731 SELECTED_TAB_OFFSET;732 infoPtr->items[curItem].rect.bottom = clientRect.top +733 infoPtr->tabHeight;734 }735 736 /*737 925 * Set the leftmost position of the tab. 738 926 */ 739 927 infoPtr->items[curItem].rect.left = curItemLeftPos; 740 928 741 if ((lStyle & TCS_FIXEDWIDTH) || ( lStyle & TCS_OWNERDRAWFIXED))929 if ((lStyle & TCS_FIXEDWIDTH) || ((lStyle & TCS_OWNERDRAWFIXED) && infoPtr->fSizeSet)) 742 930 { 743 931 infoPtr->items[curItem].rect.right = infoPtr->items[curItem].rect.left + … … 753 941 * Calculate how wide the tab is depending on the text it contains 754 942 */ 755 //SvL: Bugfix: text is unicode, not ascii756 943 GetTextExtentPoint32W(hdc, infoPtr->items[curItem].pszText, 757 944 lstrlenW(infoPtr->items[curItem].pszText), &size); … … 771 958 } 772 959 960 /* 961 * Check if this is a multiline tab control and if so 962 * check to see if we should wrap the tabs 963 * 964 * Because we are going to arange all these tabs evenly 965 * really we are basically just counting rows at this point 966 * 967 */ 968 969 if ((lStyle & TCS_MULTILINE)&& 970 (infoPtr->items[curItem].rect.right > clientRect.right)) 971 { 972 infoPtr->items[curItem].rect.right -= 973 infoPtr->items[curItem].rect.left; 974 infoPtr->items[curItem].rect.left = 0; 975 curItemRowCount ++; 976 } 977 978 infoPtr->items[curItem].rect.bottom = 0; 979 infoPtr->items[curItem].rect.top = curItemRowCount; 980 773 981 // TRACE("TextSize: %i\n ", size.cx); 774 982 // TRACE("Rect: T %i, L %i, B %i, R %i\n", … … 788 996 } 789 997 790 /* 791 * Check if we need a scrolling control. 792 */ 793 infoPtr->needsScrolling = (curItemLeftPos + (2*SELECTED_TAB_OFFSET) > 794 clientRect.right); 795 796 /* Don't need scrolling, then update infoPtr->leftmostVisible */ 797 if(!infoPtr->needsScrolling) 798 infoPtr->leftmostVisible = 0; 799 800 TAB_SetupScrolling(hwnd, infoPtr, &clientRect); 998 if (!(lStyle & TCS_MULTILINE)) 999 { 1000 /* 1001 * Check if we need a scrolling control. 1002 */ 1003 infoPtr->needsScrolling = (curItemLeftPos + (2*SELECTED_TAB_OFFSET) > 1004 clientRect.right); 1005 1006 /* Don't need scrolling, then update infoPtr->leftmostVisible */ 1007 if(!infoPtr->needsScrolling) 1008 infoPtr->leftmostVisible = 0; 1009 1010 TAB_SetupScrolling(hwnd, infoPtr, &clientRect); 1011 } 1012 1013 /* 1014 * Set the number of rows 1015 */ 1016 1017 infoPtr->uNumRows = curItemRowCount; 1018 1019 if ((lStyle & TCS_MULTILINE)&&(infoPtr->uNumItem > 0)) 1020 { 1021 INT widthDiff,remainder; 1022 INT tabPerRow,remTab; 1023 INT iRow,iItm; 1024 INT iIndexStart=0,iIndexEnd=0, iCount=0; 1025 1026 /* 1027 * Ok Microsoft trys to even out the rows. place the same 1028 * number of tabs in each row. So lets give that a shot 1029 * 1030 */ 1031 1032 tabPerRow = infoPtr->uNumItem / (infoPtr->uNumRows + 1); 1033 remTab = infoPtr->uNumItem % (infoPtr->uNumRows + 1); 1034 1035 for (iItm=0,iRow=0,iCount=0,curItemLeftPos=0; 1036 iItm<infoPtr->uNumItem; 1037 iItm++,iCount++) 1038 { 1039 if (iCount >= ((iRow<remTab)?tabPerRow+1:tabPerRow)) 1040 { 1041 iRow++; 1042 curItemLeftPos = 0; 1043 iCount = 0; 1044 } 1045 /* 1046 * normalize the current rect 1047 */ 1048 infoPtr->items[iItm].rect.right -= 1049 infoPtr->items[iItm].rect.left; 1050 infoPtr->items[iItm].rect.left = 0; 1051 1052 infoPtr->items[iItm].rect.top = iRow; 1053 infoPtr->items[iItm].rect.left +=curItemLeftPos; 1054 infoPtr->items[iItm].rect.right +=curItemLeftPos; 1055 if (lStyle & TCS_BUTTONS) 1056 curItemLeftPos = infoPtr->items[iItm].rect.right + 1057 BUTTON_SPACINGX; 1058 else 1059 curItemLeftPos = infoPtr->items[iItm].rect.right; 1060 } 1061 1062 /* 1063 * Justify the rows 1064 * 1065 */ 1066 { 1067 while(iIndexStart < infoPtr->uNumItem) 1068 { 1069 /* 1070 * find the indexs of the row 1071 */ 1072 for (iIndexEnd=iIndexStart; 1073 (iIndexEnd < infoPtr->uNumItem) && 1074 (infoPtr->items[iIndexEnd].rect.top == 1075 infoPtr->items[iIndexStart].rect.top) ; 1076 iIndexEnd++) 1077 /* intentionaly blank */; 1078 1079 /* 1080 * we need to justify these tabs so they fill the whole given 1081 * client area 1082 * 1083 */ 1084 widthDiff = clientRect.right - (2*SELECTED_TAB_OFFSET) - 1085 infoPtr->items[iIndexEnd-1].rect.right; 1086 1087 iCount = iIndexEnd-iIndexStart; 1088 1089 if (iCount) 1090 { 1091 INT iIndex; 1092 remainder = widthDiff % iCount; 1093 widthDiff = widthDiff / iCount; 1094 for (iIndex=iIndexStart,iCount=0; iIndex < iIndexEnd; 1095 iIndex++,iCount++) 1096 { 1097 infoPtr->items[iIndex].rect.left +=iCount*widthDiff; 1098 infoPtr->items[iIndex].rect.right +=(iCount+1)*widthDiff; 1099 } 1100 infoPtr->items[iIndex-1].rect.right += remainder; 1101 } 1102 1103 iIndexStart=iIndexEnd; 1104 } 1105 } 1106 } 1107 1108 TAB_EnsureSelectionVisible(hwnd,infoPtr); 1109 TAB_RecalcHotTrack(hwnd, NULL, NULL, NULL); 801 1110 802 1111 /* … … 805 1114 SelectObject (hdc, hOldFont); 806 1115 ReleaseDC (hwnd, hdc); 1116 } 1117 1118 /****************************************************************************** 1119 * TAB_DrawItemInterior 1120 * 1121 * This method is used to draw the interior (text and icon) of a single tab 1122 * into the tab control. 1123 */ 1124 static void 1125 TAB_DrawItemInterior 1126 ( 1127 HWND hwnd, 1128 HDC hdc, 1129 INT iItem, 1130 RECT* drawRect 1131 ) 1132 { 1133 TAB_INFO* infoPtr = TAB_GetInfoPtr(hwnd); 1134 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); 1135 1136 RECT localRect; 1137 1138 HPEN htextPen = GetSysColorPen (COLOR_BTNTEXT); 1139 HPEN holdPen; 1140 INT oldBkMode; 1141 1142 if (drawRect == NULL) 1143 { 1144 BOOL isVisible; 1145 RECT itemRect; 1146 RECT selectedRect; 1147 1148 /* 1149 * Get the rectangle for the item. 1150 */ 1151 isVisible = TAB_InternalGetItemRect 1152 ( 1153 hwnd, 1154 infoPtr, 1155 iItem, 1156 &itemRect, 1157 &selectedRect 1158 ); 1159 if (!isVisible) 1160 return; 1161 1162 /* 1163 * Make sure drawRect points to something valid; simplifies code. 1164 */ 1165 drawRect = &localRect; 1166 1167 /* 1168 * This logic copied from the part of TAB_DrawItem which draws 1169 * the tab background. It's important to keep it in sync. I 1170 * would have liked to avoid code duplication, but couldn't figure 1171 * out how without making spaghetti of TAB_DrawItem. 1172 */ 1173 if (lStyle & TCS_BUTTONS) 1174 { 1175 *drawRect = itemRect; 1176 if (iItem == infoPtr->iSelected) 1177 { 1178 drawRect->right--; 1179 drawRect->bottom--; 1180 } 1181 } 1182 else 1183 { 1184 if (iItem == infoPtr->iSelected) 1185 *drawRect = selectedRect; 1186 else 1187 *drawRect = itemRect; 1188 drawRect->right--; 1189 drawRect->bottom--; 1190 } 1191 } 1192 1193 /* 1194 * Text pen 1195 */ 1196 holdPen = SelectObject(hdc, htextPen); 1197 1198 oldBkMode = SetBkMode(hdc, TRANSPARENT); 1199 SetTextColor 1200 ( 1201 hdc, 1202 GetSysColor 1203 ( 1204 (iItem == infoPtr->iHotTracked) ? COLOR_HIGHLIGHT : COLOR_BTNTEXT 1205 ) 1206 ); 1207 1208 /* 1209 * Deflate the rectangle to acount for the padding 1210 */ 1211 InflateRect(drawRect, -HORIZONTAL_ITEM_PADDING, -VERTICAL_ITEM_PADDING); 1212 1213 /* 1214 * if owner draw, tell the owner to draw 1215 */ 1216 if ( (lStyle & TCS_OWNERDRAWFIXED) && GetParent(hwnd) ) 1217 { 1218 DRAWITEMSTRUCT dis; 1219 UINT id; 1220 1221 /* 1222 * get the control id 1223 */ 1224 id = GetWindowLongA(hwnd,GWL_ID); 1225 1226 /* 1227 * put together the DRAWITEMSTRUCT 1228 */ 1229 dis.CtlType = ODT_TAB; 1230 dis.CtlID = id; 1231 dis.itemID = iItem; 1232 dis.itemAction = ODA_DRAWENTIRE; 1233 if ( iItem == infoPtr->iSelected ) 1234 dis.itemState = ODS_SELECTED; 1235 else 1236 dis.itemState = 0; 1237 dis.hwndItem = hwnd; /* */ 1238 dis.hDC = hdc; 1239 dis.rcItem = *drawRect; /* */ 1240 dis.itemData = infoPtr->items[iItem].lParam; 1241 1242 /* 1243 * send the draw message 1244 */ 1245 SendMessageA( GetParent(hwnd), WM_DRAWITEM, (WPARAM)id, (LPARAM)&dis ); 1246 } 1247 else 1248 { 1249 UINT uHorizAlign; 1250 1251 /* 1252 * If not owner draw, then do the drawing ourselves. 1253 * 1254 * Draw the icon. 1255 */ 1256 if (infoPtr->himl && (infoPtr->items[iItem].mask & TCIF_IMAGE)) 1257 { 1258 INT cx; 1259 INT cy; 1260 1261 ImageList_Draw 1262 ( 1263 infoPtr->himl, 1264 infoPtr->items[iItem].iImage, 1265 hdc, 1266 drawRect->left, 1267 drawRect->top + 1, 1268 ILD_NORMAL 1269 ); 1270 ImageList_GetIconSize(infoPtr->himl, &cx, &cy); 1271 drawRect->left += (cx + HORIZONTAL_ITEM_PADDING); 1272 } 1273 1274 /* 1275 * Draw the text; 1276 */ 1277 if (lStyle & TCS_RIGHTJUSTIFY) 1278 uHorizAlign = DT_CENTER; 1279 else 1280 uHorizAlign = DT_LEFT; 1281 1282 DrawTextW 1283 ( 1284 hdc, 1285 infoPtr->items[iItem].pszText, 1286 lstrlenW(infoPtr->items[iItem].pszText), 1287 drawRect, 1288 uHorizAlign | DT_SINGLELINE | DT_VCENTER 1289 ); 1290 } 1291 1292 /* 1293 * Cleanup 1294 */ 1295 SetBkMode(hdc, oldBkMode); 1296 SelectObject(hdc, holdPen); 807 1297 } 808 1298 … … 838 1328 HPEN hwPen = GetSysColorPen (COLOR_3DHILIGHT); 839 1329 HPEN hbPen = GetSysColorPen (COLOR_BTNSHADOW); 840 HPEN hsdPen = GetSysColorPen (COLOR_BTNTEXT);841 1330 HPEN hfocusPen = CreatePen(PS_DOT, 1, GetSysColor(COLOR_BTNTEXT)); 842 1331 HPEN holdPen; 843 1332 INT oldBkMode; 844 INT cx,cy;845 1333 BOOL deleteBrush = TRUE; 846 1334 … … 859 1347 * Background color. 860 1348 */ 861 if (!( lStyle & TCS_OWNERDRAWFIXED))1349 if (!((lStyle & TCS_OWNERDRAWFIXED) && infoPtr->fSizeSet)) 862 1350 { 863 1351 COLORREF bk = GetSysColor(COLOR_3DHILIGHT); … … 867 1355 SetBkColor(hdc, bk); 868 1356 1357 /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT 1358 * we better use 0x55aa bitmap brush to make scrollbar's background 1359 * look different from the window background. 1360 */ 1361 if (bk == GetSysColor(COLOR_WINDOW)) 1362 hbr = GetPattern55AABrush(); 1363 1364 deleteBrush = FALSE; 869 1365 } 870 1366 … … 975 1471 } 976 1472 977 /*978 * Text pen979 */980 SelectObject(hdc, hsdPen);981 982 1473 oldBkMode = SetBkMode(hdc, TRANSPARENT); 983 SetTextColor (hdc, COLOR_BTNTEXT); 984 985 /* 986 * Deflate the rectangle to acount for the padding 987 */ 988 InflateRect(&r, -HORIZONTAL_ITEM_PADDING, -VERTICAL_ITEM_PADDING); 989 990 /* 991 * Draw the icon. 992 */ 993 if (infoPtr->himl) 994 { 995 ImageList_Draw (infoPtr->himl, iItem, hdc, 996 r.left, r.top+1, ILD_NORMAL); 997 ImageList_GetIconSize (infoPtr->himl, &cx, &cy); 998 r.left+=(cx + HORIZONTAL_ITEM_PADDING); 999 } 1000 1001 /* 1002 * Draw the text; 1003 */ 1004 DrawTextW(hdc, 1005 infoPtr->items[iItem].pszText, 1006 lstrlenW(infoPtr->items[iItem].pszText), 1007 &r, 1008 DT_LEFT|DT_SINGLELINE|DT_VCENTER); 1474 1475 /* This modifies r to be the text rectangle. */ 1476 TAB_DrawItemInterior(hwnd, hdc, iItem, &r); 1009 1477 1010 1478 /* … … 1032 1500 SelectObject(hdc, holdPen); 1033 1501 DeleteObject(hfocusPen); 1034 DeleteObject(hbr);1502 if (deleteBrush) DeleteObject(hbr); 1035 1503 } 1036 1504 } … … 1058 1526 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM) 1059 1527 { 1060 rect.bottom -= infoPtr->tabHeight;1528 rect.bottom -= (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2; 1061 1529 } 1062 1530 else 1063 1531 { 1064 rect.top += infoPtr->tabHeight;1532 rect.top += (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2; 1065 1533 } 1066 1534 … … 1137 1605 */ 1138 1606 TAB_DrawItem (hwnd, hdc, infoPtr->iSelected); 1607 1608 /* 1609 * If we haven't set the current focus yet, set it now. 1610 * Only happens when we first paint the tab controls. 1611 */ 1612 if (infoPtr->uFocus == -1) 1613 TAB_SetCurFocus(hwnd, infoPtr->iSelected); 1139 1614 } 1140 1615 … … 1184 1659 TAB_INFO* infoPtr) 1185 1660 { 1186 RECT selectedRect; 1187 RECT visibleRect; 1188 RECT scrollerRect; 1189 BOOL isVisible; 1661 INT iSelected = infoPtr->iSelected; 1662 1663 INT iOrigLeftmostVisible = infoPtr->leftmostVisible; 1664 1665 /* 1666 * set the items row to the bottommost row or topmost row depending on 1667 * style 1668 */ 1669 1670 if (infoPtr->uNumRows > 0) 1671 { 1672 INT newselected=infoPtr->items[iSelected].rect.top; 1673 INT iTargetRow; 1674 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); 1675 1676 if (lStyle & TCS_BOTTOM) 1677 iTargetRow = 0; 1678 else 1679 iTargetRow = infoPtr->uNumRows; 1680 1681 if (newselected != iTargetRow) 1682 { 1683 INT i; 1684 for (i=0; i < infoPtr->uNumItem; i++) 1685 if (infoPtr->items[i].rect.top == newselected ) 1686 infoPtr->items[i].rect.top = iTargetRow; 1687 else if (lStyle&TCS_BOTTOM) 1688 { 1689 if (infoPtr->items[i].rect.top < newselected) 1690 infoPtr->items[i].rect.top+=1; 1691 } 1692 else 1693 { 1694 if (infoPtr->items[i].rect.top > newselected) 1695 infoPtr->items[i].rect.top-=1; 1696 } 1697 1698 TAB_RecalcHotTrack(hwnd, NULL, NULL, NULL); 1699 } 1700 } 1190 1701 1191 1702 /* … … 1196 1707 return; 1197 1708 1198 if (infoPtr->leftmostVisible > infoPtr->iSelected) 1199 { 1200 infoPtr->leftmostVisible = infoPtr->iSelected; 1201 return; 1202 } 1203 1204 /* 1205 * Calculate the part of the client area that is visible. 1206 */ 1207 GetClientRect(hwnd, &visibleRect); 1208 GetClientRect(infoPtr->hwndUpDown, &scrollerRect); 1209 visibleRect.right -= scrollerRect.right; 1210 1211 /* 1212 * Get the rectangle for the item 1213 */ 1214 isVisible = TAB_InternalGetItemRect(hwnd, 1215 infoPtr, 1216 infoPtr->iSelected, 1217 NULL, 1218 &selectedRect); 1219 1220 /* 1221 * If this function can't say it's completely invisible, maybe it 1222 * is partially visible. Let's check. 1223 */ 1224 if (isVisible) 1225 { 1226 POINT pt1; 1227 POINT pt2; 1228 1229 pt1.x = selectedRect.left; 1230 pt1.y = selectedRect.top; 1231 pt2.x = selectedRect.right - 1; 1232 pt2.y = selectedRect.bottom - 1; 1233 1234 isVisible = PtInRect(&visibleRect, pt1) && PtInRect(&visibleRect, pt2); 1235 } 1236 1237 while ( (infoPtr->leftmostVisible < infoPtr->iSelected) && 1238 !isVisible) 1239 { 1240 infoPtr->leftmostVisible++; 1241 1242 /* 1243 * Get the rectangle for the item 1244 */ 1245 isVisible = TAB_InternalGetItemRect(hwnd, 1246 infoPtr, 1247 infoPtr->iSelected, 1248 NULL, 1249 &selectedRect); 1250 1251 /* 1252 * If this function can't say it's completely invisible, maybe it 1253 * is partially visible. Let's check. 1254 */ 1255 if (isVisible) 1256 { 1257 POINT pt1; 1258 POINT pt2; 1259 1260 pt1.x = selectedRect.left; 1261 pt1.y = selectedRect.top; 1262 pt2.x = selectedRect.right - 1; 1263 pt2.y = selectedRect.bottom - 1; 1264 1265 isVisible = PtInRect(&visibleRect, pt1) && PtInRect(&visibleRect, pt2); 1266 } 1267 } 1709 if (infoPtr->leftmostVisible >= iSelected) 1710 { 1711 infoPtr->leftmostVisible = iSelected; 1712 } 1713 else 1714 { 1715 RECT r; 1716 INT width, i; 1717 /* 1718 * Calculate the part of the client area that is visible. 1719 */ 1720 GetClientRect(hwnd, &r); 1721 width = r.right; 1722 1723 GetClientRect(infoPtr->hwndUpDown, &r); 1724 width -= r.right; 1725 1726 if ((infoPtr->items[iSelected].rect.right - 1727 infoPtr->items[iSelected].rect.left) >= width ) 1728 { 1729 /* Special case: width of selected item is greater than visible 1730 * part of control. 1731 */ 1732 infoPtr->leftmostVisible = iSelected; 1733 } 1734 else 1735 { 1736 for (i = infoPtr->leftmostVisible; i < infoPtr->uNumItem; i++) 1737 { 1738 if ((infoPtr->items[iSelected].rect.right - 1739 infoPtr->items[i].rect.left) < width) 1740 break; 1741 } 1742 infoPtr->leftmostVisible = i; 1743 } 1744 } 1745 1746 if (infoPtr->leftmostVisible != iOrigLeftmostVisible) 1747 TAB_RecalcHotTrack(hwnd, NULL, NULL, NULL); 1748 1749 SendMessageA(infoPtr->hwndUpDown, UDM_SETPOS, 0, 1750 MAKELONG(infoPtr->leftmostVisible, 0)); 1268 1751 } 1269 1752 … … 1285 1768 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM) 1286 1769 { 1287 clientRect.top = clientRect.bottom - (infoPtr->tabHeight + 1); 1770 clientRect.top = clientRect.bottom - (infoPtr->tabHeight * 1771 (infoPtr->uNumRows + 1) + 3); 1288 1772 } 1289 1773 else 1290 1774 { 1291 clientRect.bottom = clientRect.top + (infoPtr->tabHeight + 1); 1775 clientRect.bottom = clientRect.top + (infoPtr->tabHeight * 1776 (infoPtr->uNumRows + 1) + 1); 1292 1777 } 1293 1778 … … 1462 1947 } 1463 1948 1949 infoPtr->fSizeSet = TRUE; 1950 1464 1951 return lResult; 1465 1952 } … … 1494 1981 if (tabItem->mask & TCIF_TEXT) { 1495 1982 len=lstrlenA (tabItem->pszText); 1496 if (len >wineItem->cchTextMax)1497 wineItem->pszText = (WCHAR*)COMCTL32_ReAlloc (wineItem->pszText, len+1);1498 lstrcpyA ((LPSTR)wineItem->pszText,tabItem->pszText);1983 if (len > wineItem->cchTextMax) 1984 wineItem->pszText = (WCHAR*)COMCTL32_ReAlloc(wineItem->pszText,(len+1)*sizeof(WCHAR)); 1985 lstrcpyAtoW(wineItem->pszText,tabItem->pszText); 1499 1986 } 1500 1987 … … 1673 2160 infoPtr->uNumItem = 0; 1674 2161 infoPtr->iSelected = -1; 2162 if (infoPtr->iHotTracked >= 0) 2163 KillTimer(hwnd, TAB_HOTTRACK_TIMER); 2164 infoPtr->iHotTracked = -1; 2165 2166 TAB_SetItemBounds(hwnd); 2167 TAB_InvalidateTabArea(hwnd,infoPtr); 1675 2168 1676 2169 return TRUE; … … 1781 2274 1782 2275 infoPtr->uNumItem = 0; 2276 infoPtr->uNumRows = 0; 1783 2277 infoPtr->hFont = 0; 1784 2278 infoPtr->items = 0; 1785 2279 infoPtr->hcurArrow = LoadCursorA (0, IDC_ARROWA); 1786 2280 infoPtr->iSelected = -1; 1787 infoPtr->uFocus = 0; 2281 infoPtr->iHotTracked = -1; 2282 infoPtr->uFocus = -1; 1788 2283 infoPtr->hwndToolTip = 0; 1789 2284 infoPtr->DoRedraw = TRUE; … … 1791 2286 infoPtr->hwndUpDown = 0; 1792 2287 infoPtr->leftmostVisible = 0; 2288 infoPtr->fSizeSet = FALSE; 1793 2289 1794 2290 /* The tab control always has the WS_CLIPSIBLINGS style. Even … … 1847 2343 } 1848 2344 1849 if (infoPtr->hwndToolTip) 1850 DestroyWindow (infoPtr->hwndToolTip); 1851 1852 if (infoPtr->hwndUpDown) 1853 DestroyWindow(infoPtr->hwndUpDown); 2345 if (infoPtr->iHotTracked >= 0) 2346 KillTimer(hwnd, TAB_HOTTRACK_TIMER); 1854 2347 1855 2348 doneControl(hwnd); 2349 2350 return 0; 2351 } 2352 2353 static LRESULT TAB_StyleChanged(HWND hwnd,WPARAM wParam,LPARAM lParam) 2354 { 2355 TAB_SetItemBounds (hwnd); 2356 InvalidateRect(hwnd, NULL, TRUE); 1856 2357 1857 2358 return 0; … … 1930 2431 return 0; 1931 2432 1932 case TCM_GETUNICODEFORMAT:1933 // FIXME (tab, "Unimplemented msg TCM_GETUNICODEFORMAT\n");1934 return 0;1935 1936 case TCM_SETUNICODEFORMAT:1937 // FIXME (tab, "Unimplemented msg TCM_SETUNICODEFORMAT\n");1938 return 0;1939 1940 2433 case TCM_HIGHLIGHTITEM: 1941 2434 // FIXME (tab, "Unimplemented msg TCM_HIGHLIGHTITEM\n"); … … 2011 2504 case WM_HSCROLL: 2012 2505 return TAB_OnHScroll(hwnd, (int)LOWORD(wParam), (int)HIWORD(wParam), (HWND)lParam); 2506 2507 case WM_STYLECHANGED: 2508 return TAB_StyleChanged(hwnd,wParam,lParam); 2013 2509 2014 2510 case WM_KILLFOCUS: … … 2035 2531 2036 2532 ZeroMemory (&wndClass, sizeof(WNDCLASSA)); 2037 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_ SAVEBITS;2533 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; 2038 2534 wndClass.lpfnWndProc = (WNDPROC)TAB_WindowProc; 2039 2535 wndClass.cbClsExtra = 0;
Note:
See TracChangeset
for help on using the changeset viewer.