Subversion Repositories Games.Chess Giants

Rev

Rev 1 | Rev 5 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. // hyperlinks.c
  2.  
  3. #include <windows.h>
  4.  
  5.  
  6. #ifdef UNICODE
  7. #define LONGSTRING_PREFIX L
  8. #else // !UNICODE
  9. #define LONGSTRING_PREFIX
  10. #endif // UNICODE
  11.  
  12.  
  13. #define PROP_HYPERLINK_STRUCT LONGSTRING_PREFIX"_HyperlinkStruct"
  14. #define PROP_HYPERLINKPARENT_STRUCT LONGSTRING_PREFIX"_HyperlinkParentStruct"
  15.  
  16.  
  17. // standard hand cursor definition
  18. #ifndef IDC_HAND
  19. #define IDC_HAND 147
  20. #endif
  21.  
  22.  
  23. // hyperlink'ed static text control structure
  24. typedef struct hyperlink_s
  25. {
  26.    HWND hWnd; // static text control window handle
  27.    WNDPROC pfnOrigProc; // original static text control window procedure
  28.    HFONT font; // underlined hypertext font used for this control
  29. } hyperlink_t;
  30.  
  31.  
  32. // hyperlink parent window structure
  33. typedef struct hyperlinkparent_s
  34. {
  35.    HWND hWnd; // hyperlink parent window handle
  36.    WNDPROC pfnOrigProc; // original static text control window parent procedure
  37. } hyperlinkparent_t;
  38.  
  39.  
  40. // hyperlink cursor
  41. static HCURSOR hyperlink_cursor = NULL;
  42. static LOGFONT hyperlink_logicalfont;
  43.  
  44. // hyperlinks.c function prototypes
  45. void ConvertStaticToHyperlink (HWND hWndStatic);
  46. static int WINAPI _HyperlinkParentProc (HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam);
  47. static int WINAPI _HyperlinkProc (HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam);
  48.  
  49.  
  50. void ConvertStaticToHyperlink (HWND hWndStatic)
  51. {
  52.    // subclass the parent so we can color the controls as we desire
  53.  
  54.    hyperlinkparent_t *hyperlinkparent;
  55.    hyperlink_t *hyperlink;
  56.  
  57.    // first off, if the hand cursor isn't loaded yet, do it (this part is done once)
  58.    if (hyperlink_cursor == NULL)
  59.    {
  60.       // since IDC_HAND is not available on all operating systems, we will load the arrow cursor if IDC_HAND is not present.
  61.       hyperlink_cursor = LoadCursor (NULL, MAKEINTRESOURCE (IDC_HAND));
  62.       if (hyperlink_cursor == NULL)
  63.          hyperlink_cursor = LoadCursor (NULL, MAKEINTRESOURCE (IDC_ARROW)); // fallback cursor
  64.    }
  65.  
  66.    // does this control belong to a window ?
  67.    if (GetParent (hWndStatic) != NULL)
  68.    {
  69.       // mallocate space for a new hyperlink parent
  70.       hyperlinkparent = (hyperlinkparent_t *) malloc (sizeof (hyperlinkparent_t));
  71.       if (hyperlinkparent == NULL)
  72.          return; // on failure, just return
  73.  
  74.       hyperlinkparent->hWnd = GetParent (hWndStatic); // save away the hyperlink parent's window handle
  75.       hyperlinkparent->pfnOrigProc = (WNDPROC) GetWindowLong (GetParent (hWndStatic), GWL_WNDPROC); // get its current window procedure
  76.  
  77.       // has this parent NOT been already subclassed by another hyperlink ?
  78.       if (hyperlinkparent->pfnOrigProc != (WNDPROC) _HyperlinkParentProc)
  79.       {
  80.          // save a pointer to the hyperlink structure in the window's properties and subclass it by replacing its window procedure by our own
  81.          SetProp (GetParent (hWndStatic), PROP_HYPERLINKPARENT_STRUCT, (HANDLE) hyperlinkparent);
  82.          SetWindowLongPtr (GetParent (hWndStatic), GWL_WNDPROC, (long) (WNDPROC) _HyperlinkParentProc);
  83.       }
  84.    }
  85.  
  86.    // mallocate space for a new hyperlink
  87.    hyperlink = (hyperlink_t *) malloc (sizeof (hyperlink_t));
  88.    if (hyperlink == NULL)
  89.       return; // on failure, just return
  90.  
  91.    hyperlink->hWnd = hWndStatic; // get the static control's window handle
  92.    hyperlink->pfnOrigProc = (WNDPROC) GetWindowLong (hyperlink->hWnd, GWL_WNDPROC); // get the static control's window procedure
  93.  
  94.    // create an updated font by adding an underline
  95.    hyperlink->font = (HFONT) SendMessage (hyperlink->hWnd, WM_GETFONT, 0, 0);
  96.    memset (&hyperlink_logicalfont, 0, sizeof (hyperlink_logicalfont));
  97.    GetObject (hyperlink->font, sizeof (hyperlink_logicalfont), &hyperlink_logicalfont);
  98.    hyperlink_logicalfont.lfUnderline = 1;
  99.    hyperlink->font = CreateFontIndirect (&hyperlink_logicalfont);
  100.    SendMessage (hyperlink->hWnd, WM_SETFONT, (WPARAM) hyperlink->font, 0);
  101.  
  102.    // make sure the static control will send event notifications to its window procedure
  103.    SetWindowLong (hyperlink->hWnd, GWL_STYLE, GetWindowLong (hyperlink->hWnd, GWL_STYLE) | SS_NOTIFY);
  104.  
  105.    // save a pointer to the hyperlink structure in the window's properties and subclass it by replacing its window procedure by our own
  106.    SetProp (hyperlink->hWnd, PROP_HYPERLINK_STRUCT, (HANDLE) hyperlink);
  107.    SetWindowLongPtr (hyperlink->hWnd, GWL_WNDPROC, (long) (WNDPROC) _HyperlinkProc);
  108.  
  109.    return; // finished transforming the static text control
  110. }
  111.  
  112.  
  113. static int WINAPI _HyperlinkParentProc (HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam)
  114. {
  115.    // this function hooks the hyperlink parent's control drawing messages so as to draw hyperlinks differently from normal static controls
  116.  
  117.    hyperlinkparent_t *hyperlinkparent;
  118.    WNDPROC OriginalWindowProc;
  119.    LRESULT result;
  120.  
  121.    // get a pointer to the hyperlink structure
  122.    hyperlinkparent = (hyperlinkparent_t *) GetProp (hWnd, PROP_HYPERLINKPARENT_STRUCT);
  123.    if (hyperlinkparent == NULL)
  124.       return (DefWindowProc (hWnd, message, wParam, lParam)); // consistency check
  125.  
  126.    // are we drawing a static control ?
  127.    if (message == WM_CTLCOLORSTATIC)
  128.    {
  129.       result = CallWindowProc (hyperlinkparent->pfnOrigProc, hWnd, message, wParam, lParam); // call the window procedure normally
  130.       if ((WNDPROC) GetWindowLong ((HWND) lParam, GWL_WNDPROC) == (WNDPROC) _HyperlinkProc)
  131.          SetTextColor ((HDC) wParam, RGB (0, 0, 192)); // but notify the parent to draw this text in blue if it's one of our hyperlinks
  132.       return (result); // and return the original window proc return result
  133.    }
  134.  
  135.    // else are we destroying ourselves ?
  136.    else if (message == WM_DESTROY)
  137.    {
  138.       OriginalWindowProc = hyperlinkparent->pfnOrigProc;
  139.       SetWindowLongPtr (hWnd, GWL_WNDPROC, (long) OriginalWindowProc); // restore the original window procedure
  140.       if (hyperlinkparent != NULL)
  141.          free (hyperlinkparent); // free the hyperlink parent structure
  142.       hyperlinkparent = NULL;
  143.       RemoveProp (hWnd, PROP_HYPERLINKPARENT_STRUCT); // and remove the window property where we used to save it
  144.       return (OriginalWindowProc (hWnd, message, wParam, lParam)); // now call the freshly restored window procedure to let things go
  145.    }
  146.  
  147.    // now call the original window procedure to let things go normally
  148.    return (CallWindowProc (hyperlinkparent->pfnOrigProc, hWnd, message, wParam, lParam));
  149. }
  150.  
  151.  
  152. static int WINAPI _HyperlinkProc (HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam)
  153. {
  154.    // this function hooks the messages directed to the static text control that we turned into a hyperlink
  155.  
  156.    hyperlink_t *hyperlink;
  157.    WNDPROC OriginalWindowProc;
  158.  
  159.    // get a pointer to the hyperlink structure
  160.    hyperlink = (hyperlink_t *) GetProp (hWnd, PROP_HYPERLINK_STRUCT);
  161.    if (hyperlink == NULL)
  162.       return (DefWindowProc (hWnd, message, wParam, lParam)); // consistency check
  163.  
  164.    // is the mouse moving inside the static control ?
  165.    if (message == WM_SETCURSOR)
  166.    {
  167.       if (hyperlink_cursor != NULL)
  168.          SetCursor (hyperlink_cursor); // set the static control cursor to be the pointing hand, if we have it
  169.  
  170.       return (1); // halt further processing on this message
  171.    }
  172.  
  173.    // else are we destroying the static control ?
  174.    else if (message == WM_DESTROY)
  175.    {
  176.       OriginalWindowProc = hyperlink->pfnOrigProc;
  177.       SetWindowLongPtr (hWnd, GWL_WNDPROC, (long) OriginalWindowProc); // restore the original static control procedure
  178.       if (hyperlink != NULL)
  179.          free (hyperlink); // free the hyperlink structure
  180.       hyperlink = NULL;
  181.       RemoveProp (hWnd, PROP_HYPERLINK_STRUCT); // and remove the static control property where we used to save it
  182.       return (OriginalWindowProc (hWnd, message, wParam, lParam)); // now call the freshly restored window procedure to let things go
  183.    }
  184.  
  185.    // now call the original static control procedure to let things go normally
  186.    return (CallWindowProc (hyperlink->pfnOrigProc, hWnd, message, wParam, lParam));
  187. }
  188.