Subversion Repositories Games.Chess Giants

Rev

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