Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
9d6f88c9
Commit
9d6f88c9
authored
Aug 06, 2004
by
Thomas Weidenmüller
Committed by
Alexandre Julliard
Aug 06, 2004
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implemented syslink control.
parent
ecff61c8
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1752 additions
and
0 deletions
+1752
-0
Makefile.in
dlls/comctl32/Makefile.in
+1
-0
commctrl.c
dlls/comctl32/commctrl.c
+8
-0
syslink.c
dlls/comctl32/syslink.c
+1682
-0
commctrl.h
include/commctrl.h
+61
-0
No files found.
dlls/comctl32/Makefile.in
View file @
9d6f88c9
...
...
@@ -30,6 +30,7 @@ C_SRCS = \
smoothscroll.c
\
string.c
\
status.c
\
syslink.c
\
tab.c
\
toolbar.c
\
tooltips.c
\
...
...
dlls/comctl32/commctrl.c
View file @
9d6f88c9
...
...
@@ -101,6 +101,8 @@ extern void REBAR_Register(void);
extern
void
REBAR_Unregister
(
void
);
extern
void
STATUS_Register
(
void
);
extern
void
STATUS_Unregister
(
void
);
extern
void
SYSLINK_Register
(
void
);
extern
void
SYSLINK_Unregister
(
void
);
extern
void
TAB_Register
(
void
);
extern
void
TAB_Unregister
(
void
);
extern
void
TOOLBAR_Register
(
void
);
...
...
@@ -174,6 +176,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
LISTVIEW_Register
();
PROGRESS_Register
();
STATUS_Register
();
SYSLINK_Register
();
TAB_Register
();
TOOLBAR_Register
();
TOOLTIPS_Register
();
...
...
@@ -198,6 +201,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
PROGRESS_Unregister
();
REBAR_Unregister
();
STATUS_Unregister
();
SYSLINK_Unregister
();
TAB_Unregister
();
TOOLBAR_Unregister
();
TOOLTIPS_Unregister
();
...
...
@@ -711,6 +715,10 @@ InitCommonControlsEx (LPINITCOMMONCONTROLSEX lpInitCtrls)
NATIVEFONT_Register
();
break
;
case
ICC_LINK_CLASS
:
SYSLINK_Register
();
break
;
default:
FIXME
(
"Unknown class! dwICC=0x%lX
\n
"
,
dwMask
);
break
;
...
...
dlls/comctl32/syslink.c
0 → 100644
View file @
9d6f88c9
/*
* SysLink control
*
* Copyright 2004 Thomas Weidenmueller <w3seek@reactos.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* TODO:
* - Fix SHIFT+TAB and TAB issue (wrong link is selected when control gets the focus)
* - Better string parsing
* - Improve word wrapping
* - Control styles?!
*
*/
#include <stdarg.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "commctrl.h"
#include "comctl32.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL
(
progress
);
INT
WINAPI
StrCmpNIW
(
LPCWSTR
,
LPCWSTR
,
INT
);
#define SYSLINK_Alloc(size) HeapAlloc(GetProcessHeap(), 0, (size))
#define SYSLINK_Free(ptr) HeapFree(GetProcessHeap(), 0, (ptr))
#define SYSLINK_ReAlloc(ptr, size) HeapReAlloc(GetProcessHeap(), 0, ptr, (size))
typedef
struct
{
int
nChars
;
RECT
rc
;
}
DOC_TEXTBLOCK
,
*
PDOC_TEXTBLOCK
;
#define LIF_FLAGSMASK (LIF_STATE | LIF_ITEMID | LIF_URL)
#define LIS_MASK (LIS_FOCUSED | LIS_ENABLED | LIS_VISITED)
typedef
enum
{
slText
=
0
,
slLink
}
SL_ITEM_TYPE
;
typedef
struct
_DOC_ITEM
{
struct
_DOC_ITEM
*
Next
;
/* Address to the next item */
LPWSTR
Text
;
/* Text of the document item */
UINT
nText
;
/* Number of characters of the text */
SL_ITEM_TYPE
Type
;
/* type of the item */
PDOC_TEXTBLOCK
Blocks
;
/* Array of text blocks */
union
{
struct
{
UINT
state
;
/* Link state */
WCHAR
*
szID
;
/* Link ID string */
WCHAR
*
szUrl
;
/* Link URL string */
HRGN
hRgn
;
/* Region of the link */
}
Link
;
struct
{
UINT
Dummy
;
}
Text
;
}
u
;
}
DOC_ITEM
,
*
PDOC_ITEM
;
typedef
struct
{
HWND
Self
;
/* The window handle for this control */
PDOC_ITEM
Items
;
/* Address to the first document item */
BOOL
HasFocus
;
/* Whether the control has the input focus */
int
MouseDownID
;
/* ID of the link that the mouse button first selected */
HFONT
Font
;
/* Handle to the font for text */
HFONT
LinkFont
;
/* Handle to the font for links */
COLORREF
TextColor
;
/* Color of the text */
COLORREF
LinkColor
;
/* Color of links */
COLORREF
VisitedColor
;
/* Color of visited links */
}
SYSLINK_INFO
;
static
const
WCHAR
SL_LINKOPEN
[]
=
{
'<'
,
'a'
,
0
};
static
const
WCHAR
SL_HREF
[]
=
{
'h'
,
'r'
,
'e'
,
'f'
,
'='
,
'\"'
,
0
};
static
const
WCHAR
SL_ID
[]
=
{
'i'
,
'd'
,
'='
,
'\"'
,
0
};
static
const
WCHAR
SL_LINKCLOSE
[]
=
{
'<'
,
'/'
,
'a'
,
'>'
,
0
};
/* Control configuration constants */
#define SL_LEFTMARGIN (0)
#define SL_TOPMARGIN (0)
#define SL_RIGHTMARGIN (0)
#define SL_BOTTOMMARGIN (0)
/***********************************************************************
* SYSLINK_FreeDocItem
* Frees all data and gdi objects associated with a document item
*/
static
VOID
SYSLINK_FreeDocItem
(
PDOC_ITEM
DocItem
)
{
if
(
DocItem
->
Type
==
slLink
)
{
if
(
DocItem
->
u
.
Link
.
szID
!=
NULL
)
{
SYSLINK_Free
(
DocItem
->
u
.
Link
.
szID
);
}
if
(
DocItem
->
u
.
Link
.
szUrl
!=
NULL
)
{
SYSLINK_Free
(
DocItem
->
u
.
Link
.
szUrl
);
}
}
if
(
DocItem
->
Type
==
slLink
&&
DocItem
->
u
.
Link
.
hRgn
!=
NULL
)
{
DeleteObject
(
DocItem
->
u
.
Link
.
hRgn
);
}
/* we don't free Text because it's just a pointer to a character in the
entire window text string */
SYSLINK_Free
(
DocItem
);
}
/***********************************************************************
* SYSLINK_AppendDocItem
* Create and append a new document item.
*/
static
PDOC_ITEM
SYSLINK_AppendDocItem
(
SYSLINK_INFO
*
infoPtr
,
LPWSTR
Text
,
UINT
textlen
,
SL_ITEM_TYPE
type
,
PDOC_ITEM
LastItem
)
{
PDOC_ITEM
Item
;
Item
=
SYSLINK_Alloc
(
sizeof
(
DOC_ITEM
)
+
((
textlen
+
1
)
*
sizeof
(
WCHAR
)));
if
(
Item
==
NULL
)
{
ERR
(
"Failed to alloc DOC_ITEM structure!
\n
"
);
return
NULL
;
}
textlen
=
min
(
textlen
,
lstrlenW
(
Text
));
Item
->
Next
=
NULL
;
Item
->
Text
=
(
LPWSTR
)(
Item
+
1
);
Item
->
nText
=
textlen
;
Item
->
Type
=
type
;
Item
->
Blocks
=
NULL
;
if
(
LastItem
!=
NULL
)
{
LastItem
->
Next
=
Item
;
}
else
{
infoPtr
->
Items
=
Item
;
}
lstrcpynW
(
Item
->
Text
,
Text
,
textlen
+
1
);
Item
->
Text
[
textlen
]
=
0
;
return
Item
;
}
/***********************************************************************
* SYSLINK_ClearDoc
* Clears the document tree
*/
static
VOID
SYSLINK_ClearDoc
(
SYSLINK_INFO
*
infoPtr
)
{
PDOC_ITEM
Item
,
Next
;
Item
=
infoPtr
->
Items
;
while
(
Item
!=
NULL
)
{
Next
=
Item
->
Next
;
SYSLINK_FreeDocItem
(
Item
);
Item
=
Next
;
}
infoPtr
->
Items
=
NULL
;
}
/***********************************************************************
* SYSLINK_ParseText
* Parses the window text string and creates a document. Returns the
* number of document items created.
*/
static
UINT
SYSLINK_ParseText
(
SYSLINK_INFO
*
infoPtr
,
LPWSTR
Text
)
{
WCHAR
*
current
,
*
textstart
,
*
linktext
,
*
firsttag
;
int
taglen
=
0
,
textlen
,
linklen
,
docitems
=
0
;
PDOC_ITEM
Last
=
NULL
;
SL_ITEM_TYPE
CurrentType
=
slText
;
DWORD
Style
;
LPWSTR
lpID
,
lpUrl
;
UINT
lenId
,
lenUrl
;
Style
=
GetWindowLongW
(
infoPtr
->
Self
,
GWL_STYLE
);
firsttag
=
NULL
;
textstart
=
NULL
;
linktext
=
NULL
;
textlen
=
0
;
linklen
=
0
;
for
(
current
=
(
WCHAR
*
)
Text
;
*
current
!=
0
;)
{
if
(
*
current
==
'<'
)
{
if
(
!
StrCmpNIW
(
current
,
SL_LINKOPEN
,
2
)
&&
(
CurrentType
==
slText
))
{
BOOL
ValidParam
=
FALSE
,
ValidLink
=
FALSE
;
switch
(
*
(
current
+
2
))
{
case
'>'
:
/* we just have to deal with a <a> tag */
taglen
=
3
;
ValidLink
=
TRUE
;
ValidParam
=
TRUE
;
firsttag
=
current
;
linklen
=
0
;
lpID
=
NULL
;
lpUrl
=
NULL
;
break
;
case
' '
:
{
/* we expect parameters, parse them */
LPWSTR
*
CurrentParameter
=
NULL
;
UINT
*
CurrentParameterLen
=
NULL
;
WCHAR
*
tmp
;
taglen
=
3
;
tmp
=
current
+
taglen
;
lpID
=
NULL
;
lpUrl
=
NULL
;
CheckParameter:
/* compare the current position with all known parameters */
if
(
!
StrCmpNIW
(
tmp
,
SL_HREF
,
6
))
{
taglen
+=
6
;
ValidParam
=
TRUE
;
CurrentParameter
=
&
lpUrl
;
CurrentParameterLen
=
&
lenUrl
;
}
else
if
(
!
StrCmpNIW
(
tmp
,
SL_ID
,
4
))
{
taglen
+=
4
;
ValidParam
=
TRUE
;
CurrentParameter
=
&
lpID
;
CurrentParameterLen
=
&
lenId
;
}
else
{
ValidParam
=
FALSE
;
}
if
(
ValidParam
)
{
/* we got a known parameter, now search until the next " character.
If we can't find a " character, there's a syntax error and we just assume it's text */
ValidParam
=
FALSE
;
*
CurrentParameter
=
current
+
taglen
;
*
CurrentParameterLen
=
0
;
for
(
tmp
=
*
CurrentParameter
;
*
tmp
!=
0
;
tmp
++
)
{
taglen
++
;
if
(
*
tmp
==
'\"'
)
{
ValidParam
=
TRUE
;
tmp
++
;
break
;
}
(
*
CurrentParameterLen
)
++
;
}
}
if
(
ValidParam
)
{
/* we're done with this parameter, now there are only 2 possibilities:
* 1. another parameter is coming, so expect a ' ' (space) character
* 2. the tag is being closed, so expect a '<' character
*/
switch
(
*
tmp
)
{
case
' '
:
/* we expect another parameter, do the whole thing again */
taglen
++
;
tmp
++
;
goto
CheckParameter
;
case
'>'
:
/* the tag is being closed, we're done */
ValidLink
=
TRUE
;
taglen
++
;
break
;
default:
tmp
++
;
break
;
}
}
break
;
}
}
if
(
ValidLink
&&
ValidParam
)
{
/* the <a ...> tag appears to be valid. save all information
so we can add the link if we find a valid </a> tag later */
CurrentType
=
slLink
;
linktext
=
current
+
taglen
;
linklen
=
0
;
firsttag
=
current
;
}
else
{
taglen
=
1
;
lpID
=
NULL
;
lpUrl
=
NULL
;
if
(
textstart
==
NULL
)
{
textstart
=
current
;
}
}
}
else
if
(
!
StrCmpNIW
(
current
,
SL_LINKCLOSE
,
4
)
&&
(
CurrentType
==
slLink
)
&&
firsttag
)
{
/* there's a <a...> tag opened, first add the previous text, if present */
if
(
textstart
!=
NULL
&&
textlen
>
0
&&
firsttag
>
textstart
)
{
Last
=
SYSLINK_AppendDocItem
(
infoPtr
,
textstart
,
firsttag
-
textstart
,
slText
,
Last
);
if
(
Last
==
NULL
)
{
ERR
(
"Unable to create new document item!
\n
"
);
return
docitems
;
}
docitems
++
;
textstart
=
NULL
;
textlen
=
0
;
}
/* now it's time to add the link to the document */
current
+=
4
;
if
(
linktext
!=
NULL
&&
linklen
>
0
)
{
Last
=
SYSLINK_AppendDocItem
(
infoPtr
,
linktext
,
linklen
,
slLink
,
Last
);
if
(
Last
==
NULL
)
{
ERR
(
"Unable to create new document item!
\n
"
);
return
docitems
;
}
docitems
++
;
if
(
CurrentType
==
slLink
)
{
int
nc
;
if
(
!
(
Style
&
WS_DISABLED
))
{
Last
->
u
.
Link
.
state
|=
LIS_ENABLED
;
}
/* Copy the tag parameters */
if
(
lpID
!=
NULL
)
{
nc
=
min
(
lenId
,
lstrlenW
(
lpID
));
nc
=
min
(
nc
,
MAX_LINKID_TEXT
);
Last
->
u
.
Link
.
szID
=
SYSLINK_Alloc
((
MAX_LINKID_TEXT
+
1
)
*
sizeof
(
WCHAR
));
if
(
Last
->
u
.
Link
.
szID
!=
NULL
)
{
lstrcpynW
(
Last
->
u
.
Link
.
szID
,
lpID
,
nc
+
1
);
Last
->
u
.
Link
.
szID
[
nc
]
=
0
;
}
}
else
Last
->
u
.
Link
.
szID
=
NULL
;
if
(
lpUrl
!=
NULL
)
{
nc
=
min
(
lenUrl
,
lstrlenW
(
lpUrl
));
nc
=
min
(
nc
,
L_MAX_URL_LENGTH
);
Last
->
u
.
Link
.
szUrl
=
SYSLINK_Alloc
((
L_MAX_URL_LENGTH
+
1
)
*
sizeof
(
WCHAR
));
if
(
Last
->
u
.
Link
.
szUrl
!=
NULL
)
{
lstrcpynW
(
Last
->
u
.
Link
.
szUrl
,
lpUrl
,
nc
+
1
);
Last
->
u
.
Link
.
szUrl
[
nc
]
=
0
;
}
}
else
Last
->
u
.
Link
.
szUrl
=
NULL
;
}
linktext
=
NULL
;
}
CurrentType
=
slText
;
firsttag
=
NULL
;
textstart
=
NULL
;
continue
;
}
else
{
/* we don't know what tag it is, so just continue */
taglen
=
1
;
linklen
++
;
if
(
CurrentType
==
slText
&&
textstart
==
NULL
)
{
textstart
=
current
;
}
}
textlen
+=
taglen
;
current
+=
taglen
;
}
else
{
textlen
++
;
linklen
++
;
/* save the pointer of the current text item if we couldn't find a tag */
if
(
textstart
==
NULL
&&
CurrentType
==
slText
)
{
textstart
=
current
;
}
current
++
;
}
}
if
(
textstart
!=
NULL
&&
textlen
>
0
)
{
Last
=
SYSLINK_AppendDocItem
(
infoPtr
,
textstart
,
textlen
,
CurrentType
,
Last
);
if
(
Last
==
NULL
)
{
ERR
(
"Unable to create new document item!
\n
"
);
return
docitems
;
}
if
(
CurrentType
==
slLink
)
{
int
nc
;
if
(
!
(
Style
&
WS_DISABLED
))
{
Last
->
u
.
Link
.
state
|=
LIS_ENABLED
;
}
/* Copy the tag parameters */
if
(
lpID
!=
NULL
)
{
nc
=
min
(
lenId
,
lstrlenW
(
lpID
));
nc
=
min
(
nc
,
MAX_LINKID_TEXT
);
Last
->
u
.
Link
.
szID
=
SYSLINK_Alloc
((
MAX_LINKID_TEXT
+
1
)
*
sizeof
(
WCHAR
));
if
(
Last
->
u
.
Link
.
szID
!=
NULL
)
{
lstrcpynW
(
Last
->
u
.
Link
.
szID
,
lpID
,
nc
+
1
);
Last
->
u
.
Link
.
szID
[
nc
]
=
0
;
}
}
else
Last
->
u
.
Link
.
szID
=
NULL
;
if
(
lpUrl
!=
NULL
)
{
nc
=
min
(
lenUrl
,
lstrlenW
(
lpUrl
));
nc
=
min
(
nc
,
L_MAX_URL_LENGTH
);
Last
->
u
.
Link
.
szUrl
=
SYSLINK_Alloc
((
L_MAX_URL_LENGTH
+
1
)
*
sizeof
(
WCHAR
));
if
(
Last
->
u
.
Link
.
szUrl
!=
NULL
)
{
lstrcpynW
(
Last
->
u
.
Link
.
szUrl
,
lpUrl
,
nc
+
1
);
Last
->
u
.
Link
.
szUrl
[
nc
]
=
0
;
}
}
else
Last
->
u
.
Link
.
szUrl
=
NULL
;
}
docitems
++
;
}
if
(
linktext
!=
NULL
&&
linklen
>
0
)
{
/* we got a unclosed link, just display the text */
Last
=
SYSLINK_AppendDocItem
(
infoPtr
,
linktext
,
linklen
,
slText
,
Last
);
if
(
Last
==
NULL
)
{
ERR
(
"Unable to create new document item!
\n
"
);
return
docitems
;
}
docitems
++
;
}
return
docitems
;
}
/***********************************************************************
* SYSLINK_RepaintLink
* Repaints a link.
*/
static
VOID
SYSLINK_RepaintLink
(
SYSLINK_INFO
*
infoPtr
,
PDOC_ITEM
DocItem
)
{
if
(
DocItem
->
Type
!=
slLink
)
{
ERR
(
"DocItem not a link!
\n
"
);
return
;
}
if
(
DocItem
->
u
.
Link
.
hRgn
!=
NULL
)
{
/* repaint the region */
RedrawWindow
(
infoPtr
->
Self
,
NULL
,
DocItem
->
u
.
Link
.
hRgn
,
RDW_INVALIDATE
|
RDW_UPDATENOW
);
}
}
/***********************************************************************
* SYSLINK_GetLinkItemByIndex
* Retreives a document link by it's index
*/
static
PDOC_ITEM
SYSLINK_GetLinkItemByIndex
(
SYSLINK_INFO
*
infoPtr
,
int
iLink
)
{
PDOC_ITEM
Current
=
infoPtr
->
Items
;
while
(
Current
!=
NULL
)
{
if
((
Current
->
Type
==
slLink
)
&&
(
iLink
--
<=
0
))
{
return
Current
;
}
Current
=
Current
->
Next
;
}
return
NULL
;
}
/***********************************************************************
* SYSLINK_GetFocusLink
* Retreives the link that has the LIS_FOCUSED bit
*/
static
PDOC_ITEM
SYSLINK_GetFocusLink
(
SYSLINK_INFO
*
infoPtr
,
int
*
LinkId
)
{
PDOC_ITEM
Current
=
infoPtr
->
Items
;
int
id
=
0
;
while
(
Current
!=
NULL
)
{
if
((
Current
->
Type
==
slLink
))
{
if
(
Current
->
u
.
Link
.
state
&
LIS_FOCUSED
)
{
if
(
LinkId
!=
NULL
)
*
LinkId
=
id
;
return
Current
;
}
id
++
;
}
Current
=
Current
->
Next
;
}
return
NULL
;
}
/***********************************************************************
* SYSLINK_GetNextLink
* Gets the next link
*/
static
PDOC_ITEM
SYSLINK_GetNextLink
(
SYSLINK_INFO
*
infoPtr
,
PDOC_ITEM
Current
)
{
for
(
Current
=
(
Current
!=
NULL
?
Current
->
Next
:
infoPtr
->
Items
);
Current
!=
NULL
;
Current
=
Current
->
Next
)
{
if
(
Current
->
Type
==
slLink
)
{
return
Current
;
}
}
return
NULL
;
}
/***********************************************************************
* SYSLINK_GetPrevLink
* Gets the previous link
*/
static
PDOC_ITEM
SYSLINK_GetPrevLink
(
SYSLINK_INFO
*
infoPtr
,
PDOC_ITEM
Current
)
{
if
(
Current
==
NULL
)
{
/* returns the last link */
PDOC_ITEM
Last
=
NULL
;
for
(
Current
=
infoPtr
->
Items
;
Current
!=
NULL
;
Current
=
Current
->
Next
)
{
if
(
Current
->
Type
==
slLink
)
{
Last
=
Current
;
}
}
return
Last
;
}
else
{
/* returns the previous link */
PDOC_ITEM
Cur
,
Prev
=
NULL
;
for
(
Cur
=
infoPtr
->
Items
;
Cur
!=
NULL
;
Cur
=
Cur
->
Next
)
{
if
(
Cur
==
Current
)
{
break
;
}
if
(
Cur
->
Type
==
slLink
)
{
Prev
=
Cur
;
}
}
return
Prev
;
}
}
/***********************************************************************
* SYSLINK_WrapLine
* Tries to wrap a line.
*/
static
BOOL
SYSLINK_WrapLine
(
HDC
hdc
,
LPWSTR
Text
,
WCHAR
BreakChar
,
int
*
LineLen
,
int
nFit
,
LPSIZE
Extent
,
int
Width
)
{
WCHAR
*
Current
;
if
(
nFit
==
*
LineLen
)
{
return
FALSE
;
}
*
LineLen
=
nFit
;
Current
=
Text
+
nFit
;
/* check if we're in the middle of a word */
if
((
*
Current
)
!=
BreakChar
)
{
/* search for the beginning of the word */
while
(
Current
>
Text
&&
(
*
(
Current
-
1
))
!=
BreakChar
)
{
Current
--
;
(
*
LineLen
)
--
;
}
if
((
*
LineLen
)
==
0
)
{
Extent
->
cx
=
0
;
Extent
->
cy
=
0
;
}
return
TRUE
;
}
return
TRUE
;
}
/***********************************************************************
* SYSLINK_Render
* Renders the document in memory
*/
static
VOID
SYSLINK_Render
(
SYSLINK_INFO
*
infoPtr
,
HDC
hdc
)
{
RECT
rc
;
PDOC_ITEM
Current
;
HGDIOBJ
hOldFont
;
int
x
,
y
,
LineHeight
;
TEXTMETRICW
tm
;
GetClientRect
(
infoPtr
->
Self
,
&
rc
);
rc
.
right
-=
SL_RIGHTMARGIN
;
rc
.
bottom
-=
SL_BOTTOMMARGIN
;
if
(
rc
.
right
-
SL_LEFTMARGIN
<
0
||
rc
.
bottom
-
SL_TOPMARGIN
<
0
)
return
;
hOldFont
=
SelectObject
(
hdc
,
infoPtr
->
Font
);
GetTextMetricsW
(
hdc
,
&
tm
);
x
=
SL_LEFTMARGIN
;
y
=
SL_TOPMARGIN
;
LineHeight
=
0
;
for
(
Current
=
infoPtr
->
Items
;
Current
!=
NULL
;
Current
=
Current
->
Next
)
{
int
n
,
nBlocks
;
LPWSTR
tx
;
PDOC_TEXTBLOCK
bl
,
cbl
;
INT
nFit
;
SIZE
szDim
;
if
(
Current
->
nText
==
0
)
{
ERR
(
"DOC_ITEM with no text?!
\n
"
);
continue
;
}
tx
=
Current
->
Text
;
n
=
Current
->
nText
;
bl
=
Current
->
Blocks
;
nBlocks
=
0
;
if
(
Current
->
Type
==
slText
)
{
SelectObject
(
hdc
,
infoPtr
->
Font
);
}
else
if
(
Current
->
Type
==
slLink
)
{
SelectObject
(
hdc
,
infoPtr
->
LinkFont
);
}
while
(
n
>
0
)
{
if
(
GetTextExtentExPointW
(
hdc
,
tx
,
n
,
rc
.
right
-
x
,
&
nFit
,
NULL
,
&
szDim
))
{
int
LineLen
=
n
;
BOOL
Wrap
=
SYSLINK_WrapLine
(
hdc
,
tx
,
tm
.
tmBreakChar
,
&
LineLen
,
nFit
,
&
szDim
,
rc
.
right
-
x
);
if
(
LineLen
==
0
)
{
if
(
x
>
SL_LEFTMARGIN
)
{
/* move one line down, the word didn't fit into the line */
x
=
SL_LEFTMARGIN
;
y
+=
LineHeight
;
LineHeight
=
0
;
continue
;
}
else
{
/* the word starts at the beginning of the line and doesn't
fit into the line, so break it at the last character that fits */
LineLen
=
max
(
nFit
,
1
);
}
}
if
(
LineLen
!=
n
)
{
GetTextExtentExPointW
(
hdc
,
tx
,
LineLen
,
rc
.
right
-
x
,
NULL
,
NULL
,
&
szDim
);
}
if
(
bl
!=
NULL
)
{
bl
=
SYSLINK_ReAlloc
(
bl
,
++
nBlocks
*
sizeof
(
DOC_TEXTBLOCK
));
}
else
{
bl
=
SYSLINK_Alloc
(
++
nBlocks
*
sizeof
(
DOC_TEXTBLOCK
));
}
if
(
bl
!=
NULL
)
{
cbl
=
bl
+
nBlocks
-
1
;
cbl
->
nChars
=
LineLen
;
cbl
->
rc
.
left
=
x
;
cbl
->
rc
.
top
=
y
;
cbl
->
rc
.
right
=
x
+
szDim
.
cx
;
cbl
->
rc
.
bottom
=
y
+
szDim
.
cy
;
x
+=
szDim
.
cx
;
LineHeight
=
max
(
LineHeight
,
szDim
.
cy
);
/* (re)calculate the link's region */
if
(
Current
->
Type
==
slLink
)
{
if
(
nBlocks
<=
1
)
{
if
(
Current
->
u
.
Link
.
hRgn
!=
NULL
)
{
DeleteObject
(
Current
->
u
.
Link
.
hRgn
);
}
/* initialize the link's hRgn */
Current
->
u
.
Link
.
hRgn
=
CreateRectRgnIndirect
(
&
cbl
->
rc
);
}
else
if
(
Current
->
u
.
Link
.
hRgn
!=
NULL
)
{
HRGN
hrgn
;
hrgn
=
CreateRectRgnIndirect
(
&
cbl
->
rc
);
/* add the rectangle */
CombineRgn
(
Current
->
u
.
Link
.
hRgn
,
Current
->
u
.
Link
.
hRgn
,
hrgn
,
RGN_OR
);
DeleteObject
(
hrgn
);
}
}
if
(
Wrap
)
{
x
=
SL_LEFTMARGIN
;
y
+=
LineHeight
;
LineHeight
=
0
;
}
}
else
{
ERR
(
"Failed to alloc DOC_TEXTBLOCK structure!
\n
"
);
break
;
}
n
-=
LineLen
;
tx
+=
LineLen
;
}
else
{
ERR
(
"GetTextExtentExPoint() failed?!
\n
"
);
n
--
;
}
}
Current
->
Blocks
=
bl
;
}
SelectObject
(
hdc
,
hOldFont
);
}
/***********************************************************************
* SYSLINK_Draw
* Draws the SysLink control.
*/
static
LRESULT
SYSLINK_Draw
(
SYSLINK_INFO
*
infoPtr
,
HDC
hdc
)
{
RECT
rc
;
PDOC_ITEM
Current
;
HFONT
hOldFont
;
COLORREF
OldTextColor
,
OldBkColor
;
hOldFont
=
SelectObject
(
hdc
,
infoPtr
->
Font
);
OldTextColor
=
SetTextColor
(
hdc
,
infoPtr
->
TextColor
);
OldBkColor
=
SetBkColor
(
hdc
,
GetSysColor
(
COLOR_BTNFACE
));
GetClientRect
(
infoPtr
->
Self
,
&
rc
);
rc
.
right
-=
SL_RIGHTMARGIN
+
SL_LEFTMARGIN
;
rc
.
bottom
-=
SL_BOTTOMMARGIN
+
SL_TOPMARGIN
;
if
(
rc
.
right
<
0
||
rc
.
bottom
<
0
)
return
0
;
for
(
Current
=
infoPtr
->
Items
;
Current
!=
NULL
;
Current
=
Current
->
Next
)
{
int
n
;
LPWSTR
tx
;
PDOC_TEXTBLOCK
bl
;
bl
=
Current
->
Blocks
;
if
(
bl
!=
NULL
)
{
tx
=
Current
->
Text
;
n
=
Current
->
nText
;
if
(
Current
->
Type
==
slText
)
{
SelectObject
(
hdc
,
infoPtr
->
Font
);
SetTextColor
(
hdc
,
infoPtr
->
TextColor
);
}
else
{
SelectObject
(
hdc
,
infoPtr
->
LinkFont
);
SetTextColor
(
hdc
,
(
!
(
Current
->
u
.
Link
.
state
&
LIS_VISITED
)
?
infoPtr
->
LinkColor
:
infoPtr
->
VisitedColor
));
}
while
(
n
>
0
)
{
ExtTextOutW
(
hdc
,
bl
->
rc
.
left
,
bl
->
rc
.
top
,
ETO_OPAQUE
|
ETO_CLIPPED
,
&
bl
->
rc
,
tx
,
bl
->
nChars
,
NULL
);
if
((
Current
->
Type
==
slLink
)
&&
(
Current
->
u
.
Link
.
state
&
LIS_FOCUSED
)
&&
infoPtr
->
HasFocus
)
{
COLORREF
PrevColor
;
PrevColor
=
SetBkColor
(
hdc
,
OldBkColor
);
DrawFocusRect
(
hdc
,
&
bl
->
rc
);
SetBkColor
(
hdc
,
PrevColor
);
}
tx
+=
bl
->
nChars
;
n
-=
bl
->
nChars
;
bl
++
;
}
}
}
SetBkColor
(
hdc
,
OldBkColor
);
SetTextColor
(
hdc
,
OldTextColor
);
SelectObject
(
hdc
,
hOldFont
);
return
0
;
}
/***********************************************************************
* SYSLINK_Paint
* Handles the WM_PAINT message.
*/
static
LRESULT
SYSLINK_Paint
(
SYSLINK_INFO
*
infoPtr
)
{
HDC
hdc
;
PAINTSTRUCT
ps
;
hdc
=
BeginPaint
(
infoPtr
->
Self
,
&
ps
);
SYSLINK_Draw
(
infoPtr
,
hdc
);
EndPaint
(
infoPtr
->
Self
,
&
ps
);
return
0
;
}
/***********************************************************************
* SYSLINK_SetFont
* Set new Font for the SysLink control.
*/
static
HFONT
SYSLINK_SetFont
(
SYSLINK_INFO
*
infoPtr
,
HFONT
hFont
,
BOOL
bRedraw
)
{
HDC
hdc
;
LOGFONTW
lf
;
HFONT
hOldFont
=
infoPtr
->
Font
;
infoPtr
->
Font
=
hFont
;
/* free the underline font */
if
(
infoPtr
->
LinkFont
!=
NULL
)
{
DeleteObject
(
infoPtr
->
LinkFont
);
infoPtr
->
LinkFont
=
NULL
;
}
/* Render text position and word wrapping in memory */
hdc
=
GetDC
(
infoPtr
->
Self
);
if
(
hdc
!=
NULL
)
{
/* create a new underline font */
if
(
GetObjectW
(
infoPtr
->
Font
,
sizeof
(
LOGFONTW
),
&
lf
))
{
lf
.
lfUnderline
=
TRUE
;
infoPtr
->
LinkFont
=
CreateFontIndirectW
(
&
lf
);
}
else
{
ERR
(
"Failed to create link font!
\n
"
);
}
SYSLINK_Render
(
infoPtr
,
hdc
);
ReleaseDC
(
infoPtr
->
Self
,
hdc
);
}
if
(
bRedraw
)
{
RedrawWindow
(
infoPtr
->
Self
,
NULL
,
NULL
,
RDW_INVALIDATE
|
RDW_UPDATENOW
);
}
return
hOldFont
;
}
/***********************************************************************
* SYSLINK_SetText
* Set new text for the SysLink control.
*/
static
LRESULT
SYSLINK_SetText
(
SYSLINK_INFO
*
infoPtr
,
LPWSTR
Text
)
{
int
textlen
;
/* clear the document */
SYSLINK_ClearDoc
(
infoPtr
);
textlen
=
lstrlenW
(
Text
);
if
(
Text
==
NULL
||
textlen
==
0
)
{
return
TRUE
;
}
/* let's parse the string and create a document */
if
(
SYSLINK_ParseText
(
infoPtr
,
Text
)
>
0
)
{
/* Render text position and word wrapping in memory */
HDC
hdc
=
GetDC
(
infoPtr
->
Self
);
SYSLINK_Render
(
infoPtr
,
hdc
);
SYSLINK_Draw
(
infoPtr
,
hdc
);
ReleaseDC
(
infoPtr
->
Self
,
hdc
);
}
return
TRUE
;
}
/***********************************************************************
* SYSLINK_SetFocusLink
* Updates the focus status bits and focusses the specified link.
* If no document item is specified, the focus bit will be removed from all links.
* Returns the previous focused item.
*/
static
PDOC_ITEM
SYSLINK_SetFocusLink
(
SYSLINK_INFO
*
infoPtr
,
PDOC_ITEM
DocItem
)
{
PDOC_ITEM
Current
,
PrevFocus
=
NULL
;
for
(
Current
=
infoPtr
->
Items
;
Current
!=
NULL
;
Current
=
Current
->
Next
)
{
if
(
Current
->
Type
==
slLink
)
{
if
((
PrevFocus
==
NULL
)
&&
(
Current
->
u
.
Link
.
state
&
LIS_FOCUSED
))
{
PrevFocus
=
Current
;
}
if
(
Current
==
DocItem
)
{
Current
->
u
.
Link
.
state
|=
LIS_FOCUSED
;
}
else
{
Current
->
u
.
Link
.
state
&=
~
LIS_FOCUSED
;
}
}
}
return
PrevFocus
;
}
/***********************************************************************
* SYSLINK_SetItem
* Sets the states and attributes of a link item.
*/
static
LRESULT
SYSLINK_SetItem
(
SYSLINK_INFO
*
infoPtr
,
PLITEM
Item
)
{
PDOC_ITEM
di
;
BOOL
Repaint
=
FALSE
;
BOOL
Ret
=
TRUE
;
if
(
!
(
Item
->
mask
&
LIF_ITEMINDEX
)
||
!
(
Item
->
mask
&
(
LIF_FLAGSMASK
)))
{
ERR
(
"Invalid Flags!
\n
"
);
return
FALSE
;
}
di
=
SYSLINK_GetLinkItemByIndex
(
infoPtr
,
Item
->
iLink
);
if
(
di
==
NULL
)
{
ERR
(
"Link %d couldn't be found
\n
"
,
Item
->
iLink
);
return
FALSE
;
}
if
(
Item
->
mask
&
LIF_STATE
)
{
UINT
oldstate
=
di
->
u
.
Link
.
state
;
/* clear the masked bits */
di
->
u
.
Link
.
state
&=
~
(
Item
->
stateMask
&
LIS_MASK
);
/* copy the bits */
di
->
u
.
Link
.
state
|=
(
Item
->
state
&
Item
->
stateMask
)
&
LIS_MASK
;
Repaint
=
(
oldstate
!=
di
->
u
.
Link
.
state
);
/* update the focus */
SYSLINK_SetFocusLink
(
infoPtr
,
((
di
->
u
.
Link
.
state
&
LIS_FOCUSED
)
?
di
:
NULL
));
}
if
(
Item
->
mask
&
LIF_ITEMID
)
{
if
(
!
di
->
u
.
Link
.
szID
)
{
di
->
u
.
Link
.
szID
=
SYSLINK_Alloc
((
MAX_LINKID_TEXT
+
1
)
*
sizeof
(
WCHAR
));
if
(
!
Item
->
szID
)
{
ERR
(
"Unable to allocate memory for link id
\n
"
);
Ret
=
FALSE
;
}
}
if
(
di
->
u
.
Link
.
szID
)
{
lstrcpynW
(
di
->
u
.
Link
.
szID
,
Item
->
szID
,
MAX_LINKID_TEXT
+
1
);
}
}
if
(
Item
->
mask
&
LIF_URL
)
{
if
(
!
di
->
u
.
Link
.
szUrl
)
{
di
->
u
.
Link
.
szUrl
=
SYSLINK_Alloc
((
MAX_LINKID_TEXT
+
1
)
*
sizeof
(
WCHAR
));
if
(
!
Item
->
szUrl
)
{
ERR
(
"Unable to allocate memory for link url
\n
"
);
Ret
=
FALSE
;
}
}
if
(
di
->
u
.
Link
.
szUrl
)
{
lstrcpynW
(
di
->
u
.
Link
.
szUrl
,
Item
->
szUrl
,
MAX_LINKID_TEXT
+
1
);
}
}
if
(
Repaint
)
{
SYSLINK_RepaintLink
(
infoPtr
,
di
);
}
return
Ret
;
}
/***********************************************************************
* SYSLINK_GetItem
* Retrieves the states and attributes of a link item.
*/
static
LRESULT
SYSLINK_GetItem
(
SYSLINK_INFO
*
infoPtr
,
PLITEM
Item
)
{
PDOC_ITEM
di
;
if
(
!
(
Item
->
mask
&
LIF_ITEMINDEX
)
||
!
(
Item
->
mask
&
(
LIF_FLAGSMASK
)))
{
ERR
(
"Invalid Flags!
\n
"
);
return
FALSE
;
}
di
=
SYSLINK_GetLinkItemByIndex
(
infoPtr
,
Item
->
iLink
);
if
(
di
==
NULL
)
{
ERR
(
"Link %d couldn't be found
\n
"
,
Item
->
iLink
);
return
FALSE
;
}
if
(
Item
->
mask
&
LIF_STATE
)
{
Item
->
state
=
(
di
->
u
.
Link
.
state
&
Item
->
stateMask
);
if
(
!
infoPtr
->
HasFocus
)
{
/* remove the LIS_FOCUSED bit if the control doesn't have focus */
Item
->
state
&=
~
LIS_FOCUSED
;
}
}
if
(
Item
->
mask
&
LIF_ITEMID
)
{
if
(
di
->
u
.
Link
.
szID
)
{
lstrcpynW
(
Item
->
szID
,
di
->
u
.
Link
.
szID
,
MAX_LINKID_TEXT
+
1
);
}
else
{
Item
->
szID
[
0
]
=
0
;
}
}
if
(
Item
->
mask
&
LIF_URL
)
{
if
(
di
->
u
.
Link
.
szUrl
)
{
lstrcpynW
(
Item
->
szUrl
,
di
->
u
.
Link
.
szUrl
,
L_MAX_URL_LENGTH
+
1
);
}
else
{
Item
->
szUrl
[
0
]
=
0
;
}
}
return
TRUE
;
}
/***********************************************************************
* SYSLINK_HitTest
* Determines the link the user clicked on.
*/
static
LRESULT
SYSLINK_HitTest
(
SYSLINK_INFO
*
infoPtr
,
PLHITTESTINFO
HitTest
)
{
PDOC_ITEM
Current
;
int
id
=
0
;
for
(
Current
=
infoPtr
->
Items
;
Current
!=
NULL
;
Current
=
Current
->
Next
)
{
if
(
Current
->
Type
==
slLink
)
{
if
((
Current
->
u
.
Link
.
hRgn
!=
NULL
)
&&
PtInRegion
(
Current
->
u
.
Link
.
hRgn
,
HitTest
->
pt
.
x
,
HitTest
->
pt
.
y
))
{
HitTest
->
item
.
mask
=
0
;
HitTest
->
item
.
iLink
=
id
;
HitTest
->
item
.
state
=
0
;
HitTest
->
item
.
stateMask
=
0
;
if
(
Current
->
u
.
Link
.
szID
)
{
lstrcpynW
(
HitTest
->
item
.
szID
,
Current
->
u
.
Link
.
szID
,
MAX_LINKID_TEXT
+
1
);
}
else
{
HitTest
->
item
.
szID
[
0
]
=
0
;
}
if
(
Current
->
u
.
Link
.
szUrl
)
{
lstrcpynW
(
HitTest
->
item
.
szUrl
,
Current
->
u
.
Link
.
szUrl
,
L_MAX_URL_LENGTH
+
1
);
}
else
{
HitTest
->
item
.
szUrl
[
0
]
=
0
;
}
return
TRUE
;
}
id
++
;
}
}
return
FALSE
;
}
/***********************************************************************
* SYSLINK_GetIdealHeight
* Returns the preferred height of a link at the current control's width.
*/
static
LRESULT
SYSLINK_GetIdealHeight
(
SYSLINK_INFO
*
infoPtr
)
{
HDC
hdc
=
GetDC
(
infoPtr
->
Self
);
if
(
hdc
!=
NULL
)
{
LRESULT
height
;
TEXTMETRICW
tm
;
HGDIOBJ
hOldFont
=
SelectObject
(
hdc
,
infoPtr
->
Font
);
if
(
GetTextMetricsW
(
hdc
,
&
tm
))
{
height
=
tm
.
tmHeight
;
}
else
{
height
=
0
;
}
SelectObject
(
hdc
,
hOldFont
);
ReleaseDC
(
infoPtr
->
Self
,
hdc
);
return
height
;
}
return
0
;
}
/***********************************************************************
* SYSLINK_SendParentNotify
* Sends a WM_NOTIFY message to the parent window.
*/
static
LRESULT
SYSLINK_SendParentNotify
(
SYSLINK_INFO
*
infoPtr
,
UINT
code
,
PDOC_ITEM
Link
,
int
iLink
)
{
NMLINK
nml
;
nml
.
hdr
.
hwndFrom
=
infoPtr
->
Self
;
nml
.
hdr
.
idFrom
=
GetWindowLongW
(
infoPtr
->
Self
,
GWL_ID
);
nml
.
hdr
.
code
=
code
;
nml
.
item
.
mask
=
0
;
nml
.
item
.
iLink
=
iLink
;
nml
.
item
.
state
=
0
;
nml
.
item
.
stateMask
=
0
;
if
(
Link
->
u
.
Link
.
szID
)
{
lstrcpynW
(
nml
.
item
.
szID
,
Link
->
u
.
Link
.
szID
,
MAX_LINKID_TEXT
+
1
);
}
else
{
nml
.
item
.
szID
[
0
]
=
0
;
}
if
(
Link
->
u
.
Link
.
szUrl
)
{
lstrcpynW
(
nml
.
item
.
szUrl
,
Link
->
u
.
Link
.
szUrl
,
L_MAX_URL_LENGTH
+
1
);
}
else
{
nml
.
item
.
szUrl
[
0
]
=
0
;
}
return
SendMessageW
(
GetParent
(
infoPtr
->
Self
),
WM_NOTIFY
,
(
WPARAM
)
nml
.
hdr
.
idFrom
,
(
LPARAM
)
&
nml
);
}
/***********************************************************************
* SYSLINK_SetFocus
* Handles receiving the input focus.
*/
static
LRESULT
SYSLINK_SetFocus
(
SYSLINK_INFO
*
infoPtr
,
HWND
PrevFocusWindow
)
{
PDOC_ITEM
Focus
;
infoPtr
->
HasFocus
=
TRUE
;
#if 1
/* FIXME - How to detect whether SHIFT+TAB or just TAB has been pressed?
* The problem is we could get this message without keyboard input, too
*/
Focus
=
SYSLINK_GetFocusLink
(
infoPtr
,
NULL
);
if
(
Focus
==
NULL
&&
(
Focus
=
SYSLINK_GetNextLink
(
infoPtr
,
NULL
)))
{
SYSLINK_SetFocusLink
(
infoPtr
,
Focus
);
}
#else
/* This is a temporary hack since I'm not really sure how to detect which link to select.
See message above! */
Focus
=
SYSLINK_GetNextLink
(
infoPtr
,
NULL
);
if
(
Focus
!=
NULL
)
{
SYSLINK_SetFocusLink
(
infoPtr
,
Focus
);
}
#endif
SYSLINK_RepaintLink
(
infoPtr
,
Focus
);
return
0
;
}
/***********************************************************************
* SYSLINK_KillFocus
* Handles losing the input focus.
*/
static
LRESULT
SYSLINK_KillFocus
(
SYSLINK_INFO
*
infoPtr
,
HWND
NewFocusWindow
)
{
PDOC_ITEM
Focus
;
infoPtr
->
HasFocus
=
FALSE
;
Focus
=
SYSLINK_GetFocusLink
(
infoPtr
,
NULL
);
if
(
Focus
!=
NULL
)
{
SYSLINK_RepaintLink
(
infoPtr
,
Focus
);
}
return
0
;
}
/***********************************************************************
* SYSLINK_LinkAtPt
* Returns a link at the specified position
*/
static
PDOC_ITEM
SYSLINK_LinkAtPt
(
SYSLINK_INFO
*
infoPtr
,
POINT
*
pt
,
int
*
LinkId
,
BOOL
MustBeEnabled
)
{
PDOC_ITEM
Current
;
int
id
=
0
;
for
(
Current
=
infoPtr
->
Items
;
Current
!=
NULL
;
Current
=
Current
->
Next
)
{
if
((
Current
->
Type
==
slLink
)
&&
(
Current
->
u
.
Link
.
hRgn
!=
NULL
)
&&
PtInRegion
(
Current
->
u
.
Link
.
hRgn
,
pt
->
x
,
pt
->
y
)
&&
(
!
MustBeEnabled
||
(
MustBeEnabled
&&
(
Current
->
u
.
Link
.
state
&
LIS_ENABLED
))))
{
if
(
LinkId
!=
NULL
)
{
*
LinkId
=
id
;
}
return
Current
;
}
id
++
;
}
return
NULL
;
}
/***********************************************************************
* SYSLINK_LButtonDown
* Handles mouse clicks
*/
static
LRESULT
SYSLINK_LButtonDown
(
SYSLINK_INFO
*
infoPtr
,
DWORD
Buttons
,
POINT
*
pt
)
{
PDOC_ITEM
Current
,
Old
;
int
id
;
Current
=
SYSLINK_LinkAtPt
(
infoPtr
,
pt
,
&
id
,
TRUE
);
if
(
Current
!=
NULL
)
{
Old
=
SYSLINK_SetFocusLink
(
infoPtr
,
Current
);
if
(
Old
!=
NULL
&&
Old
!=
Current
)
{
SYSLINK_RepaintLink
(
infoPtr
,
Old
);
}
infoPtr
->
MouseDownID
=
id
;
SYSLINK_RepaintLink
(
infoPtr
,
Current
);
SetFocus
(
infoPtr
->
Self
);
}
return
0
;
}
/***********************************************************************
* SYSLINK_LButtonUp
* Handles mouse clicks
*/
static
LRESULT
SYSLINK_LButtonUp
(
SYSLINK_INFO
*
infoPtr
,
DWORD
Buttons
,
POINT
*
pt
)
{
if
(
infoPtr
->
MouseDownID
>
-
1
)
{
PDOC_ITEM
Current
;
int
id
;
Current
=
SYSLINK_LinkAtPt
(
infoPtr
,
pt
,
&
id
,
TRUE
);
if
((
Current
!=
NULL
)
&&
(
Current
->
u
.
Link
.
state
&
LIS_FOCUSED
)
&&
(
infoPtr
->
MouseDownID
==
id
))
{
SYSLINK_SendParentNotify
(
infoPtr
,
NM_CLICK
,
Current
,
id
);
}
}
infoPtr
->
MouseDownID
=
-
1
;
return
0
;
}
/***********************************************************************
* SYSLINK_OnEnter
* Handles ENTER key events
*/
static
BOOL
SYSLINK_OnEnter
(
SYSLINK_INFO
*
infoPtr
)
{
if
(
infoPtr
->
HasFocus
)
{
PDOC_ITEM
Focus
;
int
id
;
Focus
=
SYSLINK_GetFocusLink
(
infoPtr
,
&
id
);
if
(
Focus
!=
NULL
)
{
SYSLINK_SendParentNotify
(
infoPtr
,
NM_RETURN
,
Focus
,
id
);
return
TRUE
;
}
}
return
FALSE
;
}
/***********************************************************************
* SYSKEY_SelectNextPrevLink
* Changes the currently focused link
*/
static
BOOL
SYSKEY_SelectNextPrevLink
(
SYSLINK_INFO
*
infoPtr
,
BOOL
Prev
)
{
if
(
infoPtr
->
HasFocus
)
{
PDOC_ITEM
Focus
;
int
id
;
Focus
=
SYSLINK_GetFocusLink
(
infoPtr
,
&
id
);
if
(
Focus
!=
NULL
)
{
PDOC_ITEM
NewFocus
,
OldFocus
;
if
(
Prev
)
NewFocus
=
SYSLINK_GetPrevLink
(
infoPtr
,
Focus
);
else
NewFocus
=
SYSLINK_GetNextLink
(
infoPtr
,
Focus
);
if
(
NewFocus
!=
NULL
)
{
OldFocus
=
SYSLINK_SetFocusLink
(
infoPtr
,
NewFocus
);
if
(
OldFocus
!=
NewFocus
)
{
SYSLINK_RepaintLink
(
infoPtr
,
OldFocus
);
}
SYSLINK_RepaintLink
(
infoPtr
,
NewFocus
);
return
TRUE
;
}
}
}
return
FALSE
;
}
/***********************************************************************
* SYSKEY_SelectNextPrevLink
* Determines if there's a next or previous link to decide whether the control
* should capture the tab key message
*/
static
BOOL
SYSLINK_NoNextLink
(
SYSLINK_INFO
*
infoPtr
,
BOOL
Prev
)
{
PDOC_ITEM
Focus
,
NewFocus
;
Focus
=
SYSLINK_GetFocusLink
(
infoPtr
,
NULL
);
if
(
Prev
)
NewFocus
=
SYSLINK_GetPrevLink
(
infoPtr
,
Focus
);
else
NewFocus
=
SYSLINK_GetNextLink
(
infoPtr
,
Focus
);
return
NewFocus
==
NULL
;
}
/***********************************************************************
* SysLinkWindowProc
*/
static
LRESULT
WINAPI
SysLinkWindowProc
(
HWND
hwnd
,
UINT
message
,
WPARAM
wParam
,
LPARAM
lParam
)
{
SYSLINK_INFO
*
infoPtr
;
TRACE
(
"hwnd=%p msg=%04x wparam=%x lParam=%lx
\n
"
,
hwnd
,
message
,
wParam
,
lParam
);
infoPtr
=
(
SYSLINK_INFO
*
)
GetWindowLongW
(
hwnd
,
0
);
if
(
!
infoPtr
&&
message
!=
WM_CREATE
)
return
DefWindowProcW
(
hwnd
,
message
,
wParam
,
lParam
);
switch
(
message
)
{
case
WM_PAINT
:
return
SYSLINK_Paint
(
infoPtr
);
case
WM_SETCURSOR
:
{
LHITTESTINFO
ht
;
POINTS
pt
;
DWORD
mp
=
GetMessagePos
();
pt
=
MAKEPOINTS
(
mp
);
ht
.
pt
.
x
=
pt
.
x
;
ht
.
pt
.
y
=
pt
.
y
;
ScreenToClient
(
infoPtr
->
Self
,
&
ht
.
pt
);
if
(
SYSLINK_HitTest
(
infoPtr
,
&
ht
))
{
SetCursor
(
LoadCursorW
(
0
,
(
LPCWSTR
)
IDC_HAND
));
return
TRUE
;
}
/* let the default window proc handle this message */
return
DefWindowProcW
(
hwnd
,
message
,
wParam
,
lParam
);
}
case
WM_SIZE
:
{
HDC
hdc
=
GetDC
(
infoPtr
->
Self
);
if
(
hdc
!=
NULL
)
{
SYSLINK_Render
(
infoPtr
,
hdc
);
ReleaseDC
(
infoPtr
->
Self
,
hdc
);
}
return
0
;
}
case
WM_GETFONT
:
return
(
LRESULT
)
infoPtr
->
Font
;
case
WM_SETFONT
:
return
(
LRESULT
)
SYSLINK_SetFont
(
infoPtr
,
(
HFONT
)
wParam
,
(
BOOL
)
lParam
);
case
WM_SETTEXT
:
SYSLINK_SetText
(
infoPtr
,
(
LPWSTR
)
lParam
);
return
DefWindowProcW
(
hwnd
,
message
,
wParam
,
lParam
);
case
WM_LBUTTONDOWN
:
{
POINT
pt
;
pt
.
x
=
LOWORD
(
lParam
);
pt
.
y
=
HIWORD
(
lParam
);
return
SYSLINK_LButtonDown
(
infoPtr
,
wParam
,
&
pt
);
}
case
WM_LBUTTONUP
:
{
POINT
pt
;
pt
.
x
=
LOWORD
(
lParam
);
pt
.
y
=
HIWORD
(
lParam
);
return
SYSLINK_LButtonUp
(
infoPtr
,
wParam
,
&
pt
);
}
case
WM_KEYDOWN
:
{
switch
(
wParam
)
{
case
VK_RETURN
:
SYSLINK_OnEnter
(
infoPtr
);
return
0
;
case
VK_TAB
:
{
BOOL
shift
=
GetKeyState
(
VK_SHIFT
)
&
0x8000
;
SYSKEY_SelectNextPrevLink
(
infoPtr
,
shift
);
return
0
;
}
}
return
DefWindowProcW
(
hwnd
,
message
,
wParam
,
lParam
);
}
case
WM_GETDLGCODE
:
{
LRESULT
Ret
=
DLGC_HASSETSEL
;
int
vk
=
(
lParam
!=
0
?
(
int
)((
LPMSG
)
lParam
)
->
wParam
:
0
);
switch
(
vk
)
{
case
VK_RETURN
:
Ret
|=
DLGC_WANTMESSAGE
;
break
;
case
VK_TAB
:
{
BOOL
shift
=
GetKeyState
(
VK_SHIFT
)
&
0x8000
;
if
(
!
SYSLINK_NoNextLink
(
infoPtr
,
shift
))
{
Ret
|=
DLGC_WANTTAB
;
}
else
{
Ret
|=
DLGC_WANTCHARS
;
}
break
;
}
}
return
Ret
;
}
case
WM_NCHITTEST
:
{
POINT
pt
;
RECT
rc
;
pt
.
x
=
LOWORD
(
lParam
);
pt
.
y
=
HIWORD
(
lParam
);
GetClientRect
(
infoPtr
->
Self
,
&
rc
);
ScreenToClient
(
infoPtr
->
Self
,
&
pt
);
if
(
pt
.
x
<
0
||
pt
.
y
<
0
||
pt
.
x
>
rc
.
right
||
pt
.
y
>
rc
.
bottom
)
{
return
HTNOWHERE
;
}
if
(
SYSLINK_LinkAtPt
(
infoPtr
,
&
pt
,
NULL
,
FALSE
))
{
return
HTCLIENT
;
}
return
HTTRANSPARENT
;
}
case
LM_HITTEST
:
return
SYSLINK_HitTest
(
infoPtr
,
(
PLHITTESTINFO
)
lParam
);
case
LM_SETITEM
:
return
SYSLINK_SetItem
(
infoPtr
,
(
PLITEM
)
lParam
);
case
LM_GETITEM
:
return
SYSLINK_GetItem
(
infoPtr
,
(
PLITEM
)
lParam
);
case
LM_GETIDEALHEIGHT
:
return
SYSLINK_GetIdealHeight
(
infoPtr
);
case
WM_SETFOCUS
:
return
SYSLINK_SetFocus
(
infoPtr
,
(
HWND
)
wParam
);
case
WM_KILLFOCUS
:
return
SYSLINK_KillFocus
(
infoPtr
,
(
HWND
)
wParam
);
case
WM_CREATE
:
/* allocate memory for info struct */
infoPtr
=
(
SYSLINK_INFO
*
)
SYSLINK_Alloc
(
sizeof
(
SYSLINK_INFO
));
if
(
!
infoPtr
)
return
-
1
;
SetWindowLongW
(
hwnd
,
0
,
(
DWORD
)
infoPtr
);
/* initialize the info struct */
infoPtr
->
Self
=
hwnd
;
infoPtr
->
Font
=
0
;
infoPtr
->
LinkFont
=
0
;
infoPtr
->
Items
=
NULL
;
infoPtr
->
HasFocus
=
FALSE
;
infoPtr
->
MouseDownID
=
-
1
;
infoPtr
->
TextColor
=
GetSysColor
(
COLOR_WINDOWTEXT
);
infoPtr
->
LinkColor
=
GetSysColor
(
COLOR_HIGHLIGHT
);
infoPtr
->
VisitedColor
=
GetSysColor
(
COLOR_HIGHLIGHT
);
TRACE
(
"SysLink Ctrl creation, hwnd=%p
\n
"
,
hwnd
);
lParam
=
(
LPARAM
)(((
LPCREATESTRUCTW
)
lParam
)
->
lpszName
);
SYSLINK_SetText
(
infoPtr
,
(
LPWSTR
)
lParam
);
return
0
;
case
WM_DESTROY
:
TRACE
(
"SysLink Ctrl destruction, hwnd=%p
\n
"
,
hwnd
);
SYSLINK_ClearDoc
(
infoPtr
);
SYSLINK_Free
(
infoPtr
);
SetWindowLongW
(
hwnd
,
0
,
0
);
return
0
;
default:
if
((
message
>=
WM_USER
)
&&
(
message
<
WM_APP
))
ERR
(
"unknown msg %04x wp=%04x lp=%08lx
\n
"
,
message
,
wParam
,
lParam
);
return
DefWindowProcW
(
hwnd
,
message
,
wParam
,
lParam
);
}
}
/***********************************************************************
* SYSLINK_Register [Internal]
*
* Registers the SysLink window class.
*/
VOID
SYSLINK_Register
(
void
)
{
WNDCLASSW
wndClass
;
ZeroMemory
(
&
wndClass
,
sizeof
(
wndClass
));
wndClass
.
style
=
CS_GLOBALCLASS
|
CS_VREDRAW
|
CS_HREDRAW
;
wndClass
.
lpfnWndProc
=
(
WNDPROC
)
SysLinkWindowProc
;
wndClass
.
cbClsExtra
=
0
;
wndClass
.
cbWndExtra
=
sizeof
(
SYSLINK_INFO
*
);
wndClass
.
hCursor
=
LoadCursorW
(
0
,
(
LPWSTR
)
IDC_ARROW
);
wndClass
.
lpszClassName
=
WC_LINK
;
RegisterClassW
(
&
wndClass
);
}
/***********************************************************************
* SYSLINK_Unregister [Internal]
*
* Unregisters the SysLink window class.
*/
VOID
SYSLINK_Unregister
(
void
)
{
UnregisterClassW
(
WC_LINK
,
NULL
);
}
include/commctrl.h
View file @
9d6f88c9
...
...
@@ -4505,6 +4505,67 @@ INT WINAPI DPA_Search(HDPA, LPVOID, INT, PFNDPACOMPARE, LPARAM, UINT);
BOOL
WINAPI
Str_SetPtrW
(
LPWSTR
*
,
LPCWSTR
);
/**************************************************************************
* SysLink control
*/
#if defined(__GNUC__)
# define WC_LINK (const WCHAR []){ 'S','y','s','L','i','n','k',0 }
#elif defined(_MSC_VER)
# define WC_LINK L"SysLink"
#else
static
const
WCHAR
WC_LINK
[]
=
{
'S'
,
'y'
,
's'
,
'L'
,
'i'
,
'n'
,
'k'
,
0
};
#endif
/* SysLink messages */
#define LM_HITTEST (WM_USER + 768)
#define LM_GETIDEALHEIGHT (WM_USER + 769)
#define LM_SETITEM (WM_USER + 770)
#define LM_GETITEM (WM_USER + 771)
/* SysLink links flags */
#define LIF_ITEMINDEX 1
#define LIF_STATE 2
#define LIF_ITEMID 4
#define LIF_URL 8
/* SysLink links states */
#define LIS_FOCUSED 1
#define LIS_ENABLED 2
#define LIS_VISITED 4
/* SysLink misc. */
#define INVALID_LINK_INDEX (-1)
#define MAX_LINKID_TEXT 48
#define L_MAX_URL_LENGTH 2084
/* SysLink structures */
typedef
struct
tagLITEM
{
UINT
mask
;
int
iLink
;
UINT
state
;
UINT
stateMask
;
WCHAR
szID
[
MAX_LINKID_TEXT
];
WCHAR
szUrl
[
L_MAX_URL_LENGTH
];
}
LITEM
,
*
PLITEM
;
typedef
struct
tagLHITTESTINFO
{
POINT
pt
;
LITEM
item
;
}
LHITTESTINFO
,
*
PLHITTESTINFO
;
typedef
struct
tagNMLINK
{
NMHDR
hdr
;
LITEM
item
;
}
NMLINK
,
*
PNMLINK
;
#ifdef __cplusplus
}
#endif
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment