Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygensyslink.c
Go to the documentation of this file.
00001 /* 00002 * SysLink control 00003 * 00004 * Copyright 2004 - 2006 Thomas Weidenmueller <w3seek@reactos.com> 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00019 * 00020 * NOTES 00021 * 00022 * This code was audited for completeness against the documented features 00023 * of Comctl32.dll version 6.0 on Apr. 4, 2005, by Dimitrie O. Paun. 00024 * 00025 * Unless otherwise noted, we believe this code to be complete, as per 00026 * the specification mentioned above. 00027 * If you discover missing features, or bugs, please note them below. 00028 */ 00029 00030 #include <stdarg.h> 00031 #include <string.h> 00032 #include "windef.h" 00033 #include "winbase.h" 00034 #include "wingdi.h" 00035 #include "winuser.h" 00036 #include "winnls.h" 00037 #include "commctrl.h" 00038 #include "comctl32.h" 00039 #include "wine/unicode.h" 00040 #include "wine/debug.h" 00041 00042 WINE_DEFAULT_DEBUG_CHANNEL(syslink); 00043 00044 INT WINAPI StrCmpNIW(LPCWSTR,LPCWSTR,INT); 00045 00046 typedef struct 00047 { 00048 int nChars; 00049 int nSkip; 00050 RECT rc; 00051 } DOC_TEXTBLOCK, *PDOC_TEXTBLOCK; 00052 00053 #define LIF_FLAGSMASK (LIF_STATE | LIF_ITEMID | LIF_URL) 00054 #define LIS_MASK (LIS_FOCUSED | LIS_ENABLED | LIS_VISITED) 00055 00056 typedef enum 00057 { 00058 slText = 0, 00059 slLink 00060 } SL_ITEM_TYPE; 00061 00062 typedef struct _DOC_ITEM 00063 { 00064 struct _DOC_ITEM *Next; /* Address to the next item */ 00065 UINT nText; /* Number of characters of the text */ 00066 SL_ITEM_TYPE Type; /* type of the item */ 00067 PDOC_TEXTBLOCK Blocks; /* Array of text blocks */ 00068 union 00069 { 00070 struct 00071 { 00072 UINT state; /* Link state */ 00073 WCHAR *szID; /* Link ID string */ 00074 WCHAR *szUrl; /* Link URL string */ 00075 } Link; 00076 struct 00077 { 00078 UINT Dummy; 00079 } Text; 00080 } u; 00081 WCHAR Text[1]; /* Text of the document item */ 00082 } DOC_ITEM, *PDOC_ITEM; 00083 00084 typedef struct 00085 { 00086 HWND Self; /* The window handle for this control */ 00087 HWND Notify; /* The parent handle to receive notifications */ 00088 DWORD Style; /* Styles for this control */ 00089 PDOC_ITEM Items; /* Address to the first document item */ 00090 BOOL HasFocus; /* Whether the control has the input focus */ 00091 int MouseDownID; /* ID of the link that the mouse button first selected */ 00092 HFONT Font; /* Handle to the font for text */ 00093 HFONT LinkFont; /* Handle to the font for links */ 00094 COLORREF TextColor; /* Color of the text */ 00095 COLORREF LinkColor; /* Color of links */ 00096 COLORREF VisitedColor; /* Color of visited links */ 00097 WCHAR BreakChar; /* Break Character for the current font */ 00098 BOOL IgnoreReturn; /* (infoPtr->Style & LWS_IGNORERETURN) on creation */ 00099 } SYSLINK_INFO; 00100 00101 static const WCHAR SL_LINKOPEN[] = { '<','a', 0 }; 00102 static const WCHAR SL_HREF[] = { 'h','r','e','f','=','\"',0 }; 00103 static const WCHAR SL_ID[] = { 'i','d','=','\"',0 }; 00104 static const WCHAR SL_LINKCLOSE[] = { '<','/','a','>',0 }; 00105 00106 /* Control configuration constants */ 00107 00108 #define SL_LEFTMARGIN (0) 00109 #define SL_TOPMARGIN (0) 00110 #define SL_RIGHTMARGIN (0) 00111 #define SL_BOTTOMMARGIN (0) 00112 00113 /*********************************************************************** 00114 * SYSLINK_FreeDocItem 00115 * Frees all data and gdi objects associated with a document item 00116 */ 00117 static VOID SYSLINK_FreeDocItem (PDOC_ITEM DocItem) 00118 { 00119 if(DocItem->Type == slLink) 00120 { 00121 Free(DocItem->u.Link.szID); 00122 Free(DocItem->u.Link.szUrl); 00123 } 00124 00125 /* we don't free Text because it's just a pointer to a character in the 00126 entire window text string */ 00127 00128 Free(DocItem); 00129 } 00130 00131 /*********************************************************************** 00132 * SYSLINK_AppendDocItem 00133 * Create and append a new document item. 00134 */ 00135 static PDOC_ITEM SYSLINK_AppendDocItem (SYSLINK_INFO *infoPtr, LPCWSTR Text, UINT textlen, 00136 SL_ITEM_TYPE type, PDOC_ITEM LastItem) 00137 { 00138 PDOC_ITEM Item; 00139 00140 textlen = min(textlen, strlenW(Text)); 00141 Item = Alloc(FIELD_OFFSET(DOC_ITEM, Text[textlen + 1])); 00142 if(Item == NULL) 00143 { 00144 ERR("Failed to alloc DOC_ITEM structure!\n"); 00145 return NULL; 00146 } 00147 00148 Item->Next = NULL; 00149 Item->nText = textlen; 00150 Item->Type = type; 00151 Item->Blocks = NULL; 00152 00153 if(LastItem != NULL) 00154 { 00155 LastItem->Next = Item; 00156 } 00157 else 00158 { 00159 infoPtr->Items = Item; 00160 } 00161 00162 lstrcpynW(Item->Text, Text, textlen + 1); 00163 00164 return Item; 00165 } 00166 00167 /*********************************************************************** 00168 * SYSLINK_ClearDoc 00169 * Clears the document tree 00170 */ 00171 static VOID SYSLINK_ClearDoc (SYSLINK_INFO *infoPtr) 00172 { 00173 PDOC_ITEM Item, Next; 00174 00175 Item = infoPtr->Items; 00176 while(Item != NULL) 00177 { 00178 Next = Item->Next; 00179 SYSLINK_FreeDocItem(Item); 00180 Item = Next; 00181 } 00182 00183 infoPtr->Items = NULL; 00184 } 00185 00186 /*********************************************************************** 00187 * SYSLINK_ParseText 00188 * Parses the window text string and creates a document. Returns the 00189 * number of document items created. 00190 */ 00191 static UINT SYSLINK_ParseText (SYSLINK_INFO *infoPtr, LPCWSTR Text) 00192 { 00193 LPCWSTR current, textstart = NULL, linktext = NULL, firsttag = NULL; 00194 int taglen = 0, textlen = 0, linklen = 0, docitems = 0; 00195 PDOC_ITEM Last = NULL; 00196 SL_ITEM_TYPE CurrentType = slText; 00197 LPCWSTR lpID, lpUrl; 00198 UINT lenId, lenUrl; 00199 00200 TRACE("(%p %s)\n", infoPtr, debugstr_w(Text)); 00201 00202 for(current = Text; *current != 0;) 00203 { 00204 if(*current == '<') 00205 { 00206 if(!StrCmpNIW(current, SL_LINKOPEN, 2) && (CurrentType == slText)) 00207 { 00208 BOOL ValidParam = FALSE, ValidLink = FALSE; 00209 00210 if(*(current + 2) == '>') 00211 { 00212 /* we just have to deal with a <a> tag */ 00213 taglen = 3; 00214 ValidLink = TRUE; 00215 ValidParam = TRUE; 00216 firsttag = current; 00217 linklen = 0; 00218 lpID = NULL; 00219 lpUrl = NULL; 00220 } 00221 else if(*(current + 2) == infoPtr->BreakChar) 00222 { 00223 /* we expect parameters, parse them */ 00224 LPCWSTR *CurrentParameter = NULL, tmp; 00225 UINT *CurrentParameterLen = NULL; 00226 00227 taglen = 3; 00228 tmp = current + taglen; 00229 lpID = NULL; 00230 lpUrl = NULL; 00231 00232 CheckParameter: 00233 /* compare the current position with all known parameters */ 00234 if(!StrCmpNIW(tmp, SL_HREF, 6)) 00235 { 00236 taglen += 6; 00237 ValidParam = TRUE; 00238 CurrentParameter = &lpUrl; 00239 CurrentParameterLen = &lenUrl; 00240 } 00241 else if(!StrCmpNIW(tmp, SL_ID, 4)) 00242 { 00243 taglen += 4; 00244 ValidParam = TRUE; 00245 CurrentParameter = &lpID; 00246 CurrentParameterLen = &lenId; 00247 } 00248 else 00249 { 00250 ValidParam = FALSE; 00251 } 00252 00253 if(ValidParam) 00254 { 00255 /* we got a known parameter, now search until the next " character. 00256 If we can't find a " character, there's a syntax error and we just assume it's text */ 00257 ValidParam = FALSE; 00258 *CurrentParameter = current + taglen; 00259 *CurrentParameterLen = 0; 00260 00261 for(tmp = *CurrentParameter; *tmp != 0; tmp++) 00262 { 00263 taglen++; 00264 if(*tmp == '\"') 00265 { 00266 ValidParam = TRUE; 00267 tmp++; 00268 break; 00269 } 00270 (*CurrentParameterLen)++; 00271 } 00272 } 00273 if(ValidParam) 00274 { 00275 /* we're done with this parameter, now there are only 2 possibilities: 00276 * 1. another parameter is coming, so expect a ' ' (space) character 00277 * 2. the tag is being closed, so expect a '<' character 00278 */ 00279 if(*tmp == infoPtr->BreakChar) 00280 { 00281 /* we expect another parameter, do the whole thing again */ 00282 taglen++; 00283 tmp++; 00284 goto CheckParameter; 00285 } 00286 else if(*tmp == '>') 00287 { 00288 /* the tag is being closed, we're done */ 00289 ValidLink = TRUE; 00290 taglen++; 00291 } 00292 } 00293 } 00294 00295 if(ValidLink && ValidParam) 00296 { 00297 /* the <a ...> tag appears to be valid. save all information 00298 so we can add the link if we find a valid </a> tag later */ 00299 CurrentType = slLink; 00300 linktext = current + taglen; 00301 linklen = 0; 00302 firsttag = current; 00303 } 00304 else 00305 { 00306 taglen = 1; 00307 lpID = NULL; 00308 lpUrl = NULL; 00309 if(textstart == NULL) 00310 { 00311 textstart = current; 00312 } 00313 } 00314 } 00315 else if(!StrCmpNIW(current, SL_LINKCLOSE, 4) && (CurrentType == slLink) && firsttag) 00316 { 00317 /* there's a <a...> tag opened, first add the previous text, if present */ 00318 if(textstart != NULL && textlen > 0 && firsttag > textstart) 00319 { 00320 Last = SYSLINK_AppendDocItem(infoPtr, textstart, firsttag - textstart, slText, Last); 00321 if(Last == NULL) 00322 { 00323 ERR("Unable to create new document item!\n"); 00324 return docitems; 00325 } 00326 docitems++; 00327 textstart = NULL; 00328 textlen = 0; 00329 } 00330 00331 /* now it's time to add the link to the document */ 00332 current += 4; 00333 if(linktext != NULL && linklen > 0) 00334 { 00335 Last = SYSLINK_AppendDocItem(infoPtr, linktext, linklen, slLink, Last); 00336 if(Last == NULL) 00337 { 00338 ERR("Unable to create new document item!\n"); 00339 return docitems; 00340 } 00341 docitems++; 00342 if(CurrentType == slLink) 00343 { 00344 int nc; 00345 00346 if(!(infoPtr->Style & WS_DISABLED)) 00347 { 00348 Last->u.Link.state |= LIS_ENABLED; 00349 } 00350 /* Copy the tag parameters */ 00351 if(lpID != NULL) 00352 { 00353 nc = min(lenId, strlenW(lpID)); 00354 nc = min(nc, MAX_LINKID_TEXT - 1); 00355 Last->u.Link.szID = Alloc((nc + 1) * sizeof(WCHAR)); 00356 if(Last->u.Link.szID != NULL) 00357 { 00358 lstrcpynW(Last->u.Link.szID, lpID, nc + 1); 00359 } 00360 } 00361 else 00362 Last->u.Link.szID = NULL; 00363 if(lpUrl != NULL) 00364 { 00365 nc = min(lenUrl, strlenW(lpUrl)); 00366 nc = min(nc, L_MAX_URL_LENGTH - 1); 00367 Last->u.Link.szUrl = Alloc((nc + 1) * sizeof(WCHAR)); 00368 if(Last->u.Link.szUrl != NULL) 00369 { 00370 lstrcpynW(Last->u.Link.szUrl, lpUrl, nc + 1); 00371 } 00372 } 00373 else 00374 Last->u.Link.szUrl = NULL; 00375 } 00376 linktext = NULL; 00377 } 00378 CurrentType = slText; 00379 firsttag = NULL; 00380 textstart = NULL; 00381 continue; 00382 } 00383 else 00384 { 00385 /* we don't know what tag it is, so just continue */ 00386 taglen = 1; 00387 linklen++; 00388 if(CurrentType == slText && textstart == NULL) 00389 { 00390 textstart = current; 00391 } 00392 } 00393 00394 textlen += taglen; 00395 current += taglen; 00396 } 00397 else 00398 { 00399 textlen++; 00400 linklen++; 00401 00402 /* save the pointer of the current text item if we couldn't find a tag */ 00403 if(textstart == NULL && CurrentType == slText) 00404 { 00405 textstart = current; 00406 } 00407 00408 current++; 00409 } 00410 } 00411 00412 if(textstart != NULL && textlen > 0) 00413 { 00414 Last = SYSLINK_AppendDocItem(infoPtr, textstart, textlen, CurrentType, Last); 00415 if(Last == NULL) 00416 { 00417 ERR("Unable to create new document item!\n"); 00418 return docitems; 00419 } 00420 if(CurrentType == slLink) 00421 { 00422 int nc; 00423 00424 if(!(infoPtr->Style & WS_DISABLED)) 00425 { 00426 Last->u.Link.state |= LIS_ENABLED; 00427 } 00428 /* Copy the tag parameters */ 00429 if(lpID != NULL) 00430 { 00431 nc = min(lenId, strlenW(lpID)); 00432 nc = min(nc, MAX_LINKID_TEXT - 1); 00433 Last->u.Link.szID = Alloc((nc + 1) * sizeof(WCHAR)); 00434 if(Last->u.Link.szID != NULL) 00435 { 00436 lstrcpynW(Last->u.Link.szID, lpID, nc + 1); 00437 } 00438 } 00439 else 00440 Last->u.Link.szID = NULL; 00441 if(lpUrl != NULL) 00442 { 00443 nc = min(lenUrl, strlenW(lpUrl)); 00444 nc = min(nc, L_MAX_URL_LENGTH - 1); 00445 Last->u.Link.szUrl = Alloc((nc + 1) * sizeof(WCHAR)); 00446 if(Last->u.Link.szUrl != NULL) 00447 { 00448 lstrcpynW(Last->u.Link.szUrl, lpUrl, nc + 1); 00449 } 00450 } 00451 else 00452 Last->u.Link.szUrl = NULL; 00453 } 00454 docitems++; 00455 } 00456 00457 if(linktext != NULL && linklen > 0) 00458 { 00459 /* we got an unclosed link, just display the text */ 00460 Last = SYSLINK_AppendDocItem(infoPtr, linktext, linklen, slText, Last); 00461 if(Last == NULL) 00462 { 00463 ERR("Unable to create new document item!\n"); 00464 return docitems; 00465 } 00466 docitems++; 00467 } 00468 00469 return docitems; 00470 } 00471 00472 /*********************************************************************** 00473 * SYSLINK_RepaintLink 00474 * Repaints a link. 00475 */ 00476 static VOID SYSLINK_RepaintLink (const SYSLINK_INFO *infoPtr, const DOC_ITEM *DocItem) 00477 { 00478 PDOC_TEXTBLOCK bl; 00479 int n; 00480 00481 if(DocItem->Type != slLink) 00482 { 00483 ERR("DocItem not a link!\n"); 00484 return; 00485 } 00486 00487 bl = DocItem->Blocks; 00488 if (bl != NULL) 00489 { 00490 n = DocItem->nText; 00491 00492 while(n > 0) 00493 { 00494 InvalidateRect(infoPtr->Self, &bl->rc, TRUE); 00495 n -= bl->nChars + bl->nSkip; 00496 bl++; 00497 } 00498 } 00499 } 00500 00501 /*********************************************************************** 00502 * SYSLINK_GetLinkItemByIndex 00503 * Retrieves a document link by its index 00504 */ 00505 static PDOC_ITEM SYSLINK_GetLinkItemByIndex (const SYSLINK_INFO *infoPtr, int iLink) 00506 { 00507 PDOC_ITEM Current = infoPtr->Items; 00508 00509 while(Current != NULL) 00510 { 00511 if((Current->Type == slLink) && (iLink-- <= 0)) 00512 { 00513 return Current; 00514 } 00515 Current = Current->Next; 00516 } 00517 return NULL; 00518 } 00519 00520 /*********************************************************************** 00521 * SYSLINK_GetFocusLink 00522 * Retrieves the link that has the LIS_FOCUSED bit 00523 */ 00524 static PDOC_ITEM SYSLINK_GetFocusLink (const SYSLINK_INFO *infoPtr, int *LinkId) 00525 { 00526 PDOC_ITEM Current = infoPtr->Items; 00527 int id = 0; 00528 00529 while(Current != NULL) 00530 { 00531 if(Current->Type == slLink) 00532 { 00533 if(Current->u.Link.state & LIS_FOCUSED) 00534 { 00535 if(LinkId != NULL) 00536 *LinkId = id; 00537 return Current; 00538 } 00539 id++; 00540 } 00541 Current = Current->Next; 00542 } 00543 return NULL; 00544 } 00545 00546 /*********************************************************************** 00547 * SYSLINK_GetNextLink 00548 * Gets the next link 00549 */ 00550 static PDOC_ITEM SYSLINK_GetNextLink (const SYSLINK_INFO *infoPtr, PDOC_ITEM Current) 00551 { 00552 for(Current = (Current != NULL ? Current->Next : infoPtr->Items); 00553 Current != NULL; 00554 Current = Current->Next) 00555 { 00556 if(Current->Type == slLink) 00557 { 00558 return Current; 00559 } 00560 } 00561 return NULL; 00562 } 00563 00564 /*********************************************************************** 00565 * SYSLINK_GetPrevLink 00566 * Gets the previous link 00567 */ 00568 static PDOC_ITEM SYSLINK_GetPrevLink (const SYSLINK_INFO *infoPtr, PDOC_ITEM Current) 00569 { 00570 if(Current == NULL) 00571 { 00572 /* returns the last link */ 00573 PDOC_ITEM Last = NULL; 00574 00575 for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) 00576 { 00577 if(Current->Type == slLink) 00578 { 00579 Last = Current; 00580 } 00581 } 00582 return Last; 00583 } 00584 else 00585 { 00586 /* returns the previous link */ 00587 PDOC_ITEM Cur, Prev = NULL; 00588 00589 for(Cur = infoPtr->Items; Cur != NULL; Cur = Cur->Next) 00590 { 00591 if(Cur == Current) 00592 { 00593 break; 00594 } 00595 if(Cur->Type == slLink) 00596 { 00597 Prev = Cur; 00598 } 00599 } 00600 return Prev; 00601 } 00602 } 00603 00604 /*********************************************************************** 00605 * SYSLINK_WrapLine 00606 * Tries to wrap a line. 00607 */ 00608 static BOOL SYSLINK_WrapLine (LPWSTR Text, WCHAR BreakChar, int x, int *LineLen, 00609 int nFit, LPSIZE Extent) 00610 { 00611 int i; 00612 00613 for (i = 0; i < nFit; i++) if (Text[i] == '\n') break; 00614 00615 if (i == *LineLen) return FALSE; 00616 00617 /* check if we're in the middle of a word */ 00618 if (Text[i] != '\n' && Text[i] != BreakChar) 00619 { 00620 /* search for the beginning of the word */ 00621 while (i && Text[i - 1] != BreakChar) i--; 00622 00623 if (i == 0) 00624 { 00625 Extent->cx = 0; 00626 Extent->cy = 0; 00627 if (x == SL_LEFTMARGIN) i = max( nFit, 1 ); 00628 } 00629 } 00630 *LineLen = i; 00631 return TRUE; 00632 } 00633 00634 /*********************************************************************** 00635 * SYSLINK_Render 00636 * Renders the document in memory 00637 */ 00638 static VOID SYSLINK_Render (const SYSLINK_INFO *infoPtr, HDC hdc, PRECT pRect) 00639 { 00640 RECT rc; 00641 PDOC_ITEM Current; 00642 HGDIOBJ hOldFont; 00643 int x, y, LineHeight; 00644 SIZE szDoc; 00645 TEXTMETRICW tm; 00646 00647 szDoc.cx = szDoc.cy = 0; 00648 00649 rc = *pRect; 00650 rc.right -= SL_RIGHTMARGIN; 00651 rc.bottom -= SL_BOTTOMMARGIN; 00652 00653 if(rc.right - SL_LEFTMARGIN < 0) 00654 rc.right = MAXLONG; 00655 if (rc.bottom - SL_TOPMARGIN < 0) 00656 rc.bottom = MAXLONG; 00657 00658 hOldFont = SelectObject(hdc, infoPtr->Font); 00659 00660 x = SL_LEFTMARGIN; 00661 y = SL_TOPMARGIN; 00662 GetTextMetricsW( hdc, &tm ); 00663 LineHeight = tm.tmHeight + tm.tmExternalLeading; 00664 00665 for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) 00666 { 00667 int n, nBlocks; 00668 LPWSTR tx; 00669 PDOC_TEXTBLOCK bl, cbl; 00670 INT nFit; 00671 SIZE szDim; 00672 int SkipChars = 0; 00673 00674 if(Current->nText == 0) 00675 { 00676 continue; 00677 } 00678 00679 tx = Current->Text; 00680 n = Current->nText; 00681 00682 Free(Current->Blocks); 00683 Current->Blocks = NULL; 00684 bl = NULL; 00685 nBlocks = 0; 00686 00687 if(Current->Type == slText) 00688 { 00689 SelectObject(hdc, infoPtr->Font); 00690 } 00691 else if(Current->Type == slLink) 00692 { 00693 SelectObject(hdc, infoPtr->LinkFont); 00694 } 00695 00696 while(n > 0) 00697 { 00698 /* skip break characters unless they're the first of the doc item */ 00699 if(tx != Current->Text || x == SL_LEFTMARGIN) 00700 { 00701 if (n && *tx == '\n') 00702 { 00703 tx++; 00704 SkipChars++; 00705 n--; 00706 } 00707 while(n > 0 && (*tx) == infoPtr->BreakChar) 00708 { 00709 tx++; 00710 SkipChars++; 00711 n--; 00712 } 00713 } 00714 00715 if((n == 0 && SkipChars != 0) || 00716 GetTextExtentExPointW(hdc, tx, n, rc.right - x, &nFit, NULL, &szDim)) 00717 { 00718 int LineLen = n; 00719 BOOL Wrap = FALSE; 00720 PDOC_TEXTBLOCK nbl; 00721 00722 if(n != 0) 00723 { 00724 Wrap = SYSLINK_WrapLine(tx, infoPtr->BreakChar, x, &LineLen, nFit, &szDim); 00725 00726 if(LineLen == 0) 00727 { 00728 /* move one line down, the word didn't fit into the line */ 00729 x = SL_LEFTMARGIN; 00730 y += LineHeight; 00731 continue; 00732 } 00733 00734 if(LineLen != n) 00735 { 00736 if(!GetTextExtentExPointW(hdc, tx, LineLen, rc.right - x, NULL, NULL, &szDim)) 00737 { 00738 if(bl != NULL) 00739 { 00740 Free(bl); 00741 bl = NULL; 00742 nBlocks = 0; 00743 } 00744 break; 00745 } 00746 } 00747 } 00748 00749 nbl = ReAlloc(bl, (nBlocks + 1) * sizeof(DOC_TEXTBLOCK)); 00750 if (nbl != NULL) 00751 { 00752 bl = nbl; 00753 nBlocks++; 00754 00755 cbl = bl + nBlocks - 1; 00756 00757 cbl->nChars = LineLen; 00758 cbl->nSkip = SkipChars; 00759 cbl->rc.left = x; 00760 cbl->rc.top = y; 00761 cbl->rc.right = x + szDim.cx; 00762 cbl->rc.bottom = y + szDim.cy; 00763 00764 if (cbl->rc.right > szDoc.cx) 00765 szDoc.cx = cbl->rc.right; 00766 if (cbl->rc.bottom > szDoc.cy) 00767 szDoc.cy = cbl->rc.bottom; 00768 00769 if(LineLen != 0) 00770 { 00771 x += szDim.cx; 00772 if(Wrap) 00773 { 00774 x = SL_LEFTMARGIN; 00775 y += LineHeight; 00776 } 00777 } 00778 } 00779 else 00780 { 00781 Free(bl); 00782 bl = NULL; 00783 nBlocks = 0; 00784 00785 ERR("Failed to alloc DOC_TEXTBLOCK structure!\n"); 00786 break; 00787 } 00788 n -= LineLen; 00789 tx += LineLen; 00790 SkipChars = 0; 00791 } 00792 else 00793 { 00794 n--; 00795 } 00796 } 00797 00798 if(nBlocks != 0) 00799 { 00800 Current->Blocks = bl; 00801 } 00802 } 00803 00804 SelectObject(hdc, hOldFont); 00805 00806 pRect->right = pRect->left + szDoc.cx; 00807 pRect->bottom = pRect->top + szDoc.cy; 00808 } 00809 00810 /*********************************************************************** 00811 * SYSLINK_Draw 00812 * Draws the SysLink control. 00813 */ 00814 static LRESULT SYSLINK_Draw (const SYSLINK_INFO *infoPtr, HDC hdc) 00815 { 00816 RECT rc; 00817 PDOC_ITEM Current; 00818 HFONT hOldFont; 00819 COLORREF OldTextColor, OldBkColor; 00820 HBRUSH hBrush; 00821 UINT text_flags = ETO_CLIPPED; 00822 UINT mode = GetBkMode( hdc ); 00823 00824 hOldFont = SelectObject(hdc, infoPtr->Font); 00825 OldTextColor = SetTextColor(hdc, infoPtr->TextColor); 00826 OldBkColor = SetBkColor(hdc, comctl32_color.clrWindow); 00827 00828 GetClientRect(infoPtr->Self, &rc); 00829 rc.right -= SL_RIGHTMARGIN + SL_LEFTMARGIN; 00830 rc.bottom -= SL_BOTTOMMARGIN + SL_TOPMARGIN; 00831 00832 if(rc.right < 0 || rc.bottom < 0) return 0; 00833 00834 hBrush = (HBRUSH)SendMessageW(infoPtr->Notify, WM_CTLCOLORSTATIC, 00835 (WPARAM)hdc, (LPARAM)infoPtr->Self); 00836 if (!(infoPtr->Style & LWS_TRANSPARENT)) 00837 { 00838 FillRect(hdc, &rc, hBrush); 00839 if (GetBkMode( hdc ) == OPAQUE) text_flags |= ETO_OPAQUE; 00840 } 00841 else SetBkMode( hdc, TRANSPARENT ); 00842 00843 DeleteObject(hBrush); 00844 00845 for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) 00846 { 00847 int n; 00848 LPWSTR tx; 00849 PDOC_TEXTBLOCK bl; 00850 00851 bl = Current->Blocks; 00852 if(bl != NULL) 00853 { 00854 tx = Current->Text; 00855 n = Current->nText; 00856 00857 if(Current->Type == slText) 00858 { 00859 SelectObject(hdc, infoPtr->Font); 00860 SetTextColor(hdc, infoPtr->TextColor); 00861 } 00862 else 00863 { 00864 SelectObject(hdc, infoPtr->LinkFont); 00865 SetTextColor(hdc, (!(Current->u.Link.state & LIS_VISITED) ? infoPtr->LinkColor : infoPtr->VisitedColor)); 00866 } 00867 00868 while(n > 0) 00869 { 00870 tx += bl->nSkip; 00871 ExtTextOutW(hdc, bl->rc.left, bl->rc.top, text_flags, &bl->rc, tx, bl->nChars, NULL); 00872 if((Current->Type == slLink) && (Current->u.Link.state & LIS_FOCUSED) && infoPtr->HasFocus) 00873 { 00874 COLORREF PrevTextColor; 00875 PrevTextColor = SetTextColor(hdc, infoPtr->TextColor); 00876 DrawFocusRect(hdc, &bl->rc); 00877 SetTextColor(hdc, PrevTextColor); 00878 } 00879 tx += bl->nChars; 00880 n -= bl->nChars + bl->nSkip; 00881 bl++; 00882 } 00883 } 00884 } 00885 00886 SetBkColor(hdc, OldBkColor); 00887 SetTextColor(hdc, OldTextColor); 00888 SelectObject(hdc, hOldFont); 00889 SetBkMode(hdc, mode); 00890 return 0; 00891 } 00892 00893 00894 /*********************************************************************** 00895 * SYSLINK_Paint 00896 * Handles the WM_PAINT message. 00897 */ 00898 static LRESULT SYSLINK_Paint (const SYSLINK_INFO *infoPtr, HDC hdcParam) 00899 { 00900 HDC hdc; 00901 PAINTSTRUCT ps; 00902 00903 hdc = hdcParam ? hdcParam : BeginPaint (infoPtr->Self, &ps); 00904 if (hdc) 00905 { 00906 SYSLINK_Draw (infoPtr, hdc); 00907 if (!hdcParam) EndPaint (infoPtr->Self, &ps); 00908 } 00909 return 0; 00910 } 00911 00912 /*********************************************************************** 00913 * SYSLINK_SetFont 00914 * Set new Font for the SysLink control. 00915 */ 00916 static HFONT SYSLINK_SetFont (SYSLINK_INFO *infoPtr, HFONT hFont, BOOL bRedraw) 00917 { 00918 HDC hdc; 00919 LOGFONTW lf; 00920 TEXTMETRICW tm; 00921 RECT rcClient; 00922 HFONT hOldFont = infoPtr->Font; 00923 infoPtr->Font = hFont; 00924 00925 /* free the underline font */ 00926 if(infoPtr->LinkFont != NULL) 00927 { 00928 DeleteObject(infoPtr->LinkFont); 00929 infoPtr->LinkFont = NULL; 00930 } 00931 00932 /* Render text position and word wrapping in memory */ 00933 if (GetClientRect(infoPtr->Self, &rcClient)) 00934 { 00935 hdc = GetDC(infoPtr->Self); 00936 if(hdc != NULL) 00937 { 00938 /* create a new underline font */ 00939 if(GetTextMetricsW(hdc, &tm) && 00940 GetObjectW(infoPtr->Font, sizeof(LOGFONTW), &lf)) 00941 { 00942 lf.lfUnderline = TRUE; 00943 infoPtr->LinkFont = CreateFontIndirectW(&lf); 00944 infoPtr->BreakChar = tm.tmBreakChar; 00945 } 00946 else 00947 { 00948 ERR("Failed to create link font!\n"); 00949 } 00950 00951 SYSLINK_Render(infoPtr, hdc, &rcClient); 00952 ReleaseDC(infoPtr->Self, hdc); 00953 } 00954 } 00955 00956 if(bRedraw) 00957 { 00958 RedrawWindow(infoPtr->Self, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); 00959 } 00960 00961 return hOldFont; 00962 } 00963 00964 /*********************************************************************** 00965 * SYSLINK_SetText 00966 * Set new text for the SysLink control. 00967 */ 00968 static LRESULT SYSLINK_SetText (SYSLINK_INFO *infoPtr, LPCWSTR Text) 00969 { 00970 /* clear the document */ 00971 SYSLINK_ClearDoc(infoPtr); 00972 00973 if(Text == NULL || *Text == 0) 00974 { 00975 return TRUE; 00976 } 00977 00978 /* let's parse the string and create a document */ 00979 if(SYSLINK_ParseText(infoPtr, Text) > 0) 00980 { 00981 RECT rcClient; 00982 00983 /* Render text position and word wrapping in memory */ 00984 if (GetClientRect(infoPtr->Self, &rcClient)) 00985 { 00986 HDC hdc = GetDC(infoPtr->Self); 00987 if (hdc != NULL) 00988 { 00989 SYSLINK_Render(infoPtr, hdc, &rcClient); 00990 ReleaseDC(infoPtr->Self, hdc); 00991 00992 InvalidateRect(infoPtr->Self, NULL, TRUE); 00993 } 00994 } 00995 } 00996 00997 return TRUE; 00998 } 00999 01000 /*********************************************************************** 01001 * SYSLINK_SetFocusLink 01002 * Updates the focus status bits and focusses the specified link. 01003 * If no document item is specified, the focus bit will be removed from all links. 01004 * Returns the previous focused item. 01005 */ 01006 static PDOC_ITEM SYSLINK_SetFocusLink (const SYSLINK_INFO *infoPtr, const DOC_ITEM *DocItem) 01007 { 01008 PDOC_ITEM Current, PrevFocus = NULL; 01009 01010 for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) 01011 { 01012 if(Current->Type == slLink) 01013 { 01014 if((PrevFocus == NULL) && (Current->u.Link.state & LIS_FOCUSED)) 01015 { 01016 PrevFocus = Current; 01017 } 01018 01019 if(Current == DocItem) 01020 { 01021 Current->u.Link.state |= LIS_FOCUSED; 01022 } 01023 else 01024 { 01025 Current->u.Link.state &= ~LIS_FOCUSED; 01026 } 01027 } 01028 } 01029 01030 return PrevFocus; 01031 } 01032 01033 /*********************************************************************** 01034 * SYSLINK_SetItem 01035 * Sets the states and attributes of a link item. 01036 */ 01037 static LRESULT SYSLINK_SetItem (const SYSLINK_INFO *infoPtr, const LITEM *Item) 01038 { 01039 PDOC_ITEM di; 01040 int nc; 01041 PWSTR szId = NULL; 01042 PWSTR szUrl = NULL; 01043 BOOL Repaint = FALSE; 01044 01045 if(!(Item->mask & LIF_ITEMINDEX) || !(Item->mask & (LIF_FLAGSMASK))) 01046 { 01047 ERR("Invalid Flags!\n"); 01048 return FALSE; 01049 } 01050 01051 di = SYSLINK_GetLinkItemByIndex(infoPtr, Item->iLink); 01052 if(di == NULL) 01053 { 01054 ERR("Link %d couldn't be found\n", Item->iLink); 01055 return FALSE; 01056 } 01057 01058 if(Item->mask & LIF_ITEMID) 01059 { 01060 nc = min(lstrlenW(Item->szID), MAX_LINKID_TEXT - 1); 01061 szId = Alloc((nc + 1) * sizeof(WCHAR)); 01062 if(szId) 01063 { 01064 lstrcpynW(szId, Item->szID, nc + 1); 01065 } 01066 else 01067 { 01068 ERR("Unable to allocate memory for link id\n"); 01069 return FALSE; 01070 } 01071 } 01072 01073 if(Item->mask & LIF_URL) 01074 { 01075 nc = min(lstrlenW(Item->szUrl), L_MAX_URL_LENGTH - 1); 01076 szUrl = Alloc((nc + 1) * sizeof(WCHAR)); 01077 if(szUrl) 01078 { 01079 lstrcpynW(szUrl, Item->szUrl, nc + 1); 01080 } 01081 else 01082 { 01083 Free(szId); 01084 01085 ERR("Unable to allocate memory for link url\n"); 01086 return FALSE; 01087 } 01088 } 01089 01090 if(Item->mask & LIF_ITEMID) 01091 { 01092 Free(di->u.Link.szID); 01093 di->u.Link.szID = szId; 01094 } 01095 01096 if(Item->mask & LIF_URL) 01097 { 01098 Free(di->u.Link.szUrl); 01099 di->u.Link.szUrl = szUrl; 01100 } 01101 01102 if(Item->mask & LIF_STATE) 01103 { 01104 UINT oldstate = di->u.Link.state; 01105 /* clear the masked bits */ 01106 di->u.Link.state &= ~(Item->stateMask & LIS_MASK); 01107 /* copy the bits */ 01108 di->u.Link.state |= (Item->state & Item->stateMask) & LIS_MASK; 01109 Repaint = (oldstate != di->u.Link.state); 01110 01111 /* update the focus */ 01112 SYSLINK_SetFocusLink(infoPtr, ((di->u.Link.state & LIS_FOCUSED) ? di : NULL)); 01113 } 01114 01115 if(Repaint) 01116 { 01117 SYSLINK_RepaintLink(infoPtr, di); 01118 } 01119 01120 return TRUE; 01121 } 01122 01123 /*********************************************************************** 01124 * SYSLINK_GetItem 01125 * Retrieves the states and attributes of a link item. 01126 */ 01127 static LRESULT SYSLINK_GetItem (const SYSLINK_INFO *infoPtr, PLITEM Item) 01128 { 01129 PDOC_ITEM di; 01130 01131 if(!(Item->mask & LIF_ITEMINDEX) || !(Item->mask & (LIF_FLAGSMASK))) 01132 { 01133 ERR("Invalid Flags!\n"); 01134 return FALSE; 01135 } 01136 01137 di = SYSLINK_GetLinkItemByIndex(infoPtr, Item->iLink); 01138 if(di == NULL) 01139 { 01140 ERR("Link %d couldn't be found\n", Item->iLink); 01141 return FALSE; 01142 } 01143 01144 if(Item->mask & LIF_STATE) 01145 { 01146 Item->state = (di->u.Link.state & Item->stateMask); 01147 if(!infoPtr->HasFocus) 01148 { 01149 /* remove the LIS_FOCUSED bit if the control doesn't have focus */ 01150 Item->state &= ~LIS_FOCUSED; 01151 } 01152 } 01153 01154 if(Item->mask & LIF_ITEMID) 01155 { 01156 if(di->u.Link.szID) 01157 { 01158 lstrcpyW(Item->szID, di->u.Link.szID); 01159 } 01160 else 01161 { 01162 Item->szID[0] = 0; 01163 } 01164 } 01165 01166 if(Item->mask & LIF_URL) 01167 { 01168 if(di->u.Link.szUrl) 01169 { 01170 lstrcpyW(Item->szUrl, di->u.Link.szUrl); 01171 } 01172 else 01173 { 01174 Item->szUrl[0] = 0; 01175 } 01176 } 01177 01178 return TRUE; 01179 } 01180 01181 /*********************************************************************** 01182 * SYSLINK_PtInDocItem 01183 * Determines if a point is in the region of a document item 01184 */ 01185 static BOOL SYSLINK_PtInDocItem (const DOC_ITEM *DocItem, POINT pt) 01186 { 01187 PDOC_TEXTBLOCK bl; 01188 int n; 01189 01190 bl = DocItem->Blocks; 01191 if (bl != NULL) 01192 { 01193 n = DocItem->nText; 01194 01195 while(n > 0) 01196 { 01197 if (PtInRect(&bl->rc, pt)) 01198 { 01199 return TRUE; 01200 } 01201 n -= bl->nChars + bl->nSkip; 01202 bl++; 01203 } 01204 } 01205 01206 return FALSE; 01207 } 01208 01209 /*********************************************************************** 01210 * SYSLINK_HitTest 01211 * Determines the link the user clicked on. 01212 */ 01213 static LRESULT SYSLINK_HitTest (const SYSLINK_INFO *infoPtr, PLHITTESTINFO HitTest) 01214 { 01215 PDOC_ITEM Current; 01216 int id = 0; 01217 01218 for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) 01219 { 01220 if(Current->Type == slLink) 01221 { 01222 if(SYSLINK_PtInDocItem(Current, HitTest->pt)) 01223 { 01224 HitTest->item.mask = 0; 01225 HitTest->item.iLink = id; 01226 HitTest->item.state = 0; 01227 HitTest->item.stateMask = 0; 01228 if(Current->u.Link.szID) 01229 { 01230 lstrcpyW(HitTest->item.szID, Current->u.Link.szID); 01231 } 01232 else 01233 { 01234 HitTest->item.szID[0] = 0; 01235 } 01236 if(Current->u.Link.szUrl) 01237 { 01238 lstrcpyW(HitTest->item.szUrl, Current->u.Link.szUrl); 01239 } 01240 else 01241 { 01242 HitTest->item.szUrl[0] = 0; 01243 } 01244 return TRUE; 01245 } 01246 id++; 01247 } 01248 } 01249 01250 return FALSE; 01251 } 01252 01253 /*********************************************************************** 01254 * SYSLINK_GetIdealHeight 01255 * Returns the preferred height of a link at the current control's width. 01256 */ 01257 static LRESULT SYSLINK_GetIdealHeight (const SYSLINK_INFO *infoPtr) 01258 { 01259 HDC hdc = GetDC(infoPtr->Self); 01260 if(hdc != NULL) 01261 { 01262 LRESULT height; 01263 TEXTMETRICW tm; 01264 HGDIOBJ hOldFont = SelectObject(hdc, infoPtr->Font); 01265 01266 if(GetTextMetricsW(hdc, &tm)) 01267 { 01268 height = tm.tmHeight; 01269 } 01270 else 01271 { 01272 height = 0; 01273 } 01274 SelectObject(hdc, hOldFont); 01275 ReleaseDC(infoPtr->Self, hdc); 01276 01277 return height; 01278 } 01279 return 0; 01280 } 01281 01282 /*********************************************************************** 01283 * SYSLINK_SendParentNotify 01284 * Sends a WM_NOTIFY message to the parent window. 01285 */ 01286 static LRESULT SYSLINK_SendParentNotify (const SYSLINK_INFO *infoPtr, UINT code, const DOC_ITEM *Link, int iLink) 01287 { 01288 NMLINK nml; 01289 01290 nml.hdr.hwndFrom = infoPtr->Self; 01291 nml.hdr.idFrom = GetWindowLongPtrW(infoPtr->Self, GWLP_ID); 01292 nml.hdr.code = code; 01293 01294 nml.item.mask = 0; 01295 nml.item.iLink = iLink; 01296 nml.item.state = 0; 01297 nml.item.stateMask = 0; 01298 if(Link->u.Link.szID) 01299 { 01300 lstrcpyW(nml.item.szID, Link->u.Link.szID); 01301 } 01302 else 01303 { 01304 nml.item.szID[0] = 0; 01305 } 01306 if(Link->u.Link.szUrl) 01307 { 01308 lstrcpyW(nml.item.szUrl, Link->u.Link.szUrl); 01309 } 01310 else 01311 { 01312 nml.item.szUrl[0] = 0; 01313 } 01314 01315 return SendMessageW(infoPtr->Notify, WM_NOTIFY, nml.hdr.idFrom, (LPARAM)&nml); 01316 } 01317 01318 /*********************************************************************** 01319 * SYSLINK_SetFocus 01320 * Handles receiving the input focus. 01321 */ 01322 static LRESULT SYSLINK_SetFocus (SYSLINK_INFO *infoPtr) 01323 { 01324 PDOC_ITEM Focus; 01325 01326 infoPtr->HasFocus = TRUE; 01327 01328 /* We always select the first link, even if we activated the control using 01329 SHIFT+TAB. This is the default behavior */ 01330 Focus = SYSLINK_GetNextLink(infoPtr, NULL); 01331 if(Focus != NULL) 01332 { 01333 SYSLINK_SetFocusLink(infoPtr, Focus); 01334 SYSLINK_RepaintLink(infoPtr, Focus); 01335 } 01336 return 0; 01337 } 01338 01339 /*********************************************************************** 01340 * SYSLINK_KillFocus 01341 * Handles losing the input focus. 01342 */ 01343 static LRESULT SYSLINK_KillFocus (SYSLINK_INFO *infoPtr) 01344 { 01345 PDOC_ITEM Focus; 01346 01347 infoPtr->HasFocus = FALSE; 01348 Focus = SYSLINK_GetFocusLink(infoPtr, NULL); 01349 01350 if(Focus != NULL) 01351 { 01352 SYSLINK_RepaintLink(infoPtr, Focus); 01353 } 01354 01355 return 0; 01356 } 01357 01358 /*********************************************************************** 01359 * SYSLINK_LinkAtPt 01360 * Returns a link at the specified position 01361 */ 01362 static PDOC_ITEM SYSLINK_LinkAtPt (const SYSLINK_INFO *infoPtr, const POINT *pt, int *LinkId, BOOL MustBeEnabled) 01363 { 01364 PDOC_ITEM Current; 01365 int id = 0; 01366 01367 for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) 01368 { 01369 if((Current->Type == slLink) && SYSLINK_PtInDocItem(Current, *pt) && 01370 (!MustBeEnabled || (MustBeEnabled && (Current->u.Link.state & LIS_ENABLED)))) 01371 { 01372 if(LinkId != NULL) 01373 { 01374 *LinkId = id; 01375 } 01376 return Current; 01377 } 01378 id++; 01379 } 01380 01381 return NULL; 01382 } 01383 01384 /*********************************************************************** 01385 * SYSLINK_LButtonDown 01386 * Handles mouse clicks 01387 */ 01388 static LRESULT SYSLINK_LButtonDown (SYSLINK_INFO *infoPtr, const POINT *pt) 01389 { 01390 PDOC_ITEM Current, Old; 01391 int id; 01392 01393 Current = SYSLINK_LinkAtPt(infoPtr, pt, &id, TRUE); 01394 if(Current != NULL) 01395 { 01396 SetFocus(infoPtr->Self); 01397 01398 Old = SYSLINK_SetFocusLink(infoPtr, Current); 01399 if(Old != NULL && Old != Current) 01400 { 01401 SYSLINK_RepaintLink(infoPtr, Old); 01402 } 01403 infoPtr->MouseDownID = id; 01404 SYSLINK_RepaintLink(infoPtr, Current); 01405 } 01406 01407 return 0; 01408 } 01409 01410 /*********************************************************************** 01411 * SYSLINK_LButtonUp 01412 * Handles mouse clicks 01413 */ 01414 static LRESULT SYSLINK_LButtonUp (SYSLINK_INFO *infoPtr, const POINT *pt) 01415 { 01416 if(infoPtr->MouseDownID > -1) 01417 { 01418 PDOC_ITEM Current; 01419 int id; 01420 01421 Current = SYSLINK_LinkAtPt(infoPtr, pt, &id, TRUE); 01422 if((Current != NULL) && (Current->u.Link.state & LIS_FOCUSED) && (infoPtr->MouseDownID == id)) 01423 { 01424 SYSLINK_SendParentNotify(infoPtr, NM_CLICK, Current, id); 01425 } 01426 } 01427 01428 infoPtr->MouseDownID = -1; 01429 01430 return 0; 01431 } 01432 01433 /*********************************************************************** 01434 * SYSLINK_OnEnter 01435 * Handles ENTER key events 01436 */ 01437 static BOOL SYSLINK_OnEnter (const SYSLINK_INFO *infoPtr) 01438 { 01439 if(infoPtr->HasFocus && !infoPtr->IgnoreReturn) 01440 { 01441 PDOC_ITEM Focus; 01442 int id; 01443 01444 Focus = SYSLINK_GetFocusLink(infoPtr, &id); 01445 if(Focus) 01446 { 01447 SYSLINK_SendParentNotify(infoPtr, NM_RETURN, Focus, id); 01448 return TRUE; 01449 } 01450 } 01451 return FALSE; 01452 } 01453 01454 /*********************************************************************** 01455 * SYSKEY_SelectNextPrevLink 01456 * Changes the currently focused link 01457 */ 01458 static BOOL SYSKEY_SelectNextPrevLink (const SYSLINK_INFO *infoPtr, BOOL Prev) 01459 { 01460 if(infoPtr->HasFocus) 01461 { 01462 PDOC_ITEM Focus; 01463 int id; 01464 01465 Focus = SYSLINK_GetFocusLink(infoPtr, &id); 01466 if(Focus != NULL) 01467 { 01468 PDOC_ITEM NewFocus, OldFocus; 01469 01470 if(Prev) 01471 NewFocus = SYSLINK_GetPrevLink(infoPtr, Focus); 01472 else 01473 NewFocus = SYSLINK_GetNextLink(infoPtr, Focus); 01474 01475 if(NewFocus != NULL) 01476 { 01477 OldFocus = SYSLINK_SetFocusLink(infoPtr, NewFocus); 01478 01479 if(OldFocus && OldFocus != NewFocus) 01480 { 01481 SYSLINK_RepaintLink(infoPtr, OldFocus); 01482 } 01483 SYSLINK_RepaintLink(infoPtr, NewFocus); 01484 return TRUE; 01485 } 01486 } 01487 } 01488 return FALSE; 01489 } 01490 01491 /*********************************************************************** 01492 * SYSKEY_SelectNextPrevLink 01493 * Determines if there's a next or previous link to decide whether the control 01494 * should capture the tab key message 01495 */ 01496 static BOOL SYSLINK_NoNextLink (const SYSLINK_INFO *infoPtr, BOOL Prev) 01497 { 01498 PDOC_ITEM Focus, NewFocus; 01499 01500 Focus = SYSLINK_GetFocusLink(infoPtr, NULL); 01501 if(Prev) 01502 NewFocus = SYSLINK_GetPrevLink(infoPtr, Focus); 01503 else 01504 NewFocus = SYSLINK_GetNextLink(infoPtr, Focus); 01505 01506 return NewFocus == NULL; 01507 } 01508 01509 /*********************************************************************** 01510 * SYSLINK_GetIdealSize 01511 * Calculates the ideal size of a link control at a given maximum width. 01512 */ 01513 static VOID SYSLINK_GetIdealSize (const SYSLINK_INFO *infoPtr, int cxMaxWidth, LPSIZE lpSize) 01514 { 01515 RECT rc; 01516 HDC hdc; 01517 01518 rc.left = rc.top = rc.bottom = 0; 01519 rc.right = cxMaxWidth; 01520 01521 hdc = GetDC(infoPtr->Self); 01522 if (hdc != NULL) 01523 { 01524 HGDIOBJ hOldFont = SelectObject(hdc, infoPtr->Font); 01525 01526 SYSLINK_Render(infoPtr, hdc, &rc); 01527 01528 SelectObject(hdc, hOldFont); 01529 ReleaseDC(infoPtr->Self, hdc); 01530 01531 lpSize->cx = rc.right; 01532 lpSize->cy = rc.bottom; 01533 } 01534 } 01535 01536 /*********************************************************************** 01537 * SysLinkWindowProc 01538 */ 01539 static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message, 01540 WPARAM wParam, LPARAM lParam) 01541 { 01542 SYSLINK_INFO *infoPtr; 01543 01544 TRACE("hwnd=%p msg=%04x wparam=%lx lParam=%lx\n", hwnd, message, wParam, lParam); 01545 01546 infoPtr = (SYSLINK_INFO *)GetWindowLongPtrW(hwnd, 0); 01547 01548 if (!infoPtr && message != WM_CREATE) 01549 return DefWindowProcW(hwnd, message, wParam, lParam); 01550 01551 switch(message) { 01552 case WM_PRINTCLIENT: 01553 case WM_PAINT: 01554 return SYSLINK_Paint (infoPtr, (HDC)wParam); 01555 01556 case WM_ERASEBKGND: 01557 if (!(infoPtr->Style & LWS_TRANSPARENT)) 01558 { 01559 HDC hdc = (HDC)wParam; 01560 HBRUSH brush = CreateSolidBrush( comctl32_color.clrWindow ); 01561 RECT rect; 01562 01563 GetClipBox( hdc, &rect ); 01564 FillRect( hdc, &rect, brush ); 01565 DeleteObject( brush ); 01566 return 1; 01567 } 01568 return 0; 01569 01570 case WM_SETCURSOR: 01571 { 01572 LHITTESTINFO ht; 01573 DWORD mp = GetMessagePos(); 01574 01575 ht.pt.x = (short)LOWORD(mp); 01576 ht.pt.y = (short)HIWORD(mp); 01577 01578 ScreenToClient(infoPtr->Self, &ht.pt); 01579 if(SYSLINK_HitTest (infoPtr, &ht)) 01580 { 01581 SetCursor(LoadCursorW(0, (LPCWSTR)IDC_HAND)); 01582 return TRUE; 01583 } 01584 01585 return DefWindowProcW(hwnd, message, wParam, lParam); 01586 } 01587 01588 case WM_SIZE: 01589 { 01590 RECT rcClient; 01591 if (GetClientRect(infoPtr->Self, &rcClient)) 01592 { 01593 HDC hdc = GetDC(infoPtr->Self); 01594 if(hdc != NULL) 01595 { 01596 SYSLINK_Render(infoPtr, hdc, &rcClient); 01597 ReleaseDC(infoPtr->Self, hdc); 01598 } 01599 } 01600 return 0; 01601 } 01602 01603 case WM_GETFONT: 01604 return (LRESULT)infoPtr->Font; 01605 01606 case WM_SETFONT: 01607 return (LRESULT)SYSLINK_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam); 01608 01609 case WM_SETTEXT: 01610 SYSLINK_SetText(infoPtr, (LPWSTR)lParam); 01611 return DefWindowProcW(hwnd, message, wParam, lParam); 01612 01613 case WM_LBUTTONDOWN: 01614 { 01615 POINT pt; 01616 pt.x = (short)LOWORD(lParam); 01617 pt.y = (short)HIWORD(lParam); 01618 return SYSLINK_LButtonDown(infoPtr, &pt); 01619 } 01620 case WM_LBUTTONUP: 01621 { 01622 POINT pt; 01623 pt.x = (short)LOWORD(lParam); 01624 pt.y = (short)HIWORD(lParam); 01625 return SYSLINK_LButtonUp(infoPtr, &pt); 01626 } 01627 01628 case WM_KEYDOWN: 01629 { 01630 switch(wParam) 01631 { 01632 case VK_RETURN: 01633 SYSLINK_OnEnter(infoPtr); 01634 return 0; 01635 case VK_TAB: 01636 { 01637 BOOL shift = GetKeyState(VK_SHIFT) & 0x8000; 01638 SYSKEY_SelectNextPrevLink(infoPtr, shift); 01639 return 0; 01640 } 01641 default: 01642 return DefWindowProcW(hwnd, message, wParam, lParam); 01643 } 01644 } 01645 01646 case WM_GETDLGCODE: 01647 { 01648 LRESULT Ret = DLGC_HASSETSEL; 01649 int vk = (lParam != 0 ? (int)((LPMSG)lParam)->wParam : 0); 01650 switch(vk) 01651 { 01652 case VK_RETURN: 01653 Ret |= DLGC_WANTMESSAGE; 01654 break; 01655 case VK_TAB: 01656 { 01657 BOOL shift = GetKeyState(VK_SHIFT) & 0x8000; 01658 if(!SYSLINK_NoNextLink(infoPtr, shift)) 01659 { 01660 Ret |= DLGC_WANTTAB; 01661 } 01662 else 01663 { 01664 Ret |= DLGC_WANTCHARS; 01665 } 01666 break; 01667 } 01668 } 01669 return Ret; 01670 } 01671 01672 case WM_NCHITTEST: 01673 { 01674 POINT pt; 01675 RECT rc; 01676 pt.x = (short)LOWORD(lParam); 01677 pt.y = (short)HIWORD(lParam); 01678 01679 GetClientRect(infoPtr->Self, &rc); 01680 ScreenToClient(infoPtr->Self, &pt); 01681 if(pt.x < 0 || pt.y < 0 || pt.x > rc.right || pt.y > rc.bottom) 01682 { 01683 return HTNOWHERE; 01684 } 01685 01686 if(SYSLINK_LinkAtPt(infoPtr, &pt, NULL, FALSE)) 01687 { 01688 return HTCLIENT; 01689 } 01690 01691 return HTTRANSPARENT; 01692 } 01693 01694 case LM_HITTEST: 01695 return SYSLINK_HitTest(infoPtr, (PLHITTESTINFO)lParam); 01696 01697 case LM_SETITEM: 01698 return SYSLINK_SetItem(infoPtr, (PLITEM)lParam); 01699 01700 case LM_GETITEM: 01701 return SYSLINK_GetItem(infoPtr, (PLITEM)lParam); 01702 01703 case LM_GETIDEALHEIGHT: 01704 if (lParam) 01705 { 01706 /* LM_GETIDEALSIZE */ 01707 SYSLINK_GetIdealSize(infoPtr, (int)wParam, (LPSIZE)lParam); 01708 } 01709 return SYSLINK_GetIdealHeight(infoPtr); 01710 01711 case WM_SETFOCUS: 01712 return SYSLINK_SetFocus(infoPtr); 01713 01714 case WM_KILLFOCUS: 01715 return SYSLINK_KillFocus(infoPtr); 01716 01717 case WM_ENABLE: 01718 infoPtr->Style &= ~WS_DISABLED; 01719 infoPtr->Style |= (wParam ? 0 : WS_DISABLED); 01720 InvalidateRect (infoPtr->Self, NULL, FALSE); 01721 return 0; 01722 01723 case WM_STYLECHANGED: 01724 if (wParam == GWL_STYLE) 01725 { 01726 infoPtr->Style = ((LPSTYLESTRUCT)lParam)->styleNew; 01727 01728 InvalidateRect(infoPtr->Self, NULL, TRUE); 01729 } 01730 return 0; 01731 01732 case WM_CREATE: 01733 /* allocate memory for info struct */ 01734 infoPtr = Alloc (sizeof(SYSLINK_INFO)); 01735 if (!infoPtr) return -1; 01736 SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); 01737 01738 /* initialize the info struct */ 01739 infoPtr->Self = hwnd; 01740 infoPtr->Notify = ((LPCREATESTRUCTW)lParam)->hwndParent; 01741 infoPtr->Style = ((LPCREATESTRUCTW)lParam)->style; 01742 infoPtr->Font = 0; 01743 infoPtr->LinkFont = 0; 01744 infoPtr->Items = NULL; 01745 infoPtr->HasFocus = FALSE; 01746 infoPtr->MouseDownID = -1; 01747 infoPtr->TextColor = comctl32_color.clrWindowText; 01748 infoPtr->LinkColor = comctl32_color.clrHighlight; 01749 infoPtr->VisitedColor = comctl32_color.clrHighlight; 01750 infoPtr->BreakChar = ' '; 01751 infoPtr->IgnoreReturn = infoPtr->Style & LWS_IGNORERETURN; 01752 TRACE("SysLink Ctrl creation, hwnd=%p\n", hwnd); 01753 SYSLINK_SetText(infoPtr, ((LPCREATESTRUCTW)lParam)->lpszName); 01754 return 0; 01755 01756 case WM_DESTROY: 01757 TRACE("SysLink Ctrl destruction, hwnd=%p\n", hwnd); 01758 SYSLINK_ClearDoc(infoPtr); 01759 if(infoPtr->Font != 0) DeleteObject(infoPtr->Font); 01760 if(infoPtr->LinkFont != 0) DeleteObject(infoPtr->LinkFont); 01761 SetWindowLongPtrW(hwnd, 0, 0); 01762 Free (infoPtr); 01763 return 0; 01764 01765 case WM_SYSCOLORCHANGE: 01766 COMCTL32_RefreshSysColors(); 01767 return 0; 01768 01769 default: 01770 if ((message >= WM_USER) && (message < WM_APP) && !COMCTL32_IsReflectedMessage(message)) 01771 { 01772 ERR("unknown msg %04x wp=%04lx lp=%08lx\n", message, wParam, lParam ); 01773 } 01774 return DefWindowProcW(hwnd, message, wParam, lParam); 01775 } 01776 } 01777 01778 01779 /*********************************************************************** 01780 * SYSLINK_Register [Internal] 01781 * 01782 * Registers the SysLink window class. 01783 */ 01784 VOID SYSLINK_Register (void) 01785 { 01786 WNDCLASSW wndClass; 01787 01788 ZeroMemory (&wndClass, sizeof(wndClass)); 01789 wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW; 01790 wndClass.lpfnWndProc = SysLinkWindowProc; 01791 wndClass.cbClsExtra = 0; 01792 wndClass.cbWndExtra = sizeof (SYSLINK_INFO *); 01793 wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); 01794 wndClass.lpszClassName = WC_LINK; 01795 01796 RegisterClassW (&wndClass); 01797 } 01798 01799 01800 /*********************************************************************** 01801 * SYSLINK_Unregister [Internal] 01802 * 01803 * Unregisters the SysLink window class. 01804 */ 01805 VOID SYSLINK_Unregister (void) 01806 { 01807 UnregisterClassW (WC_LINK, NULL); 01808 } Generated on Sat May 26 2012 04:21:38 for ReactOS by
1.7.6.1
|