#include "wx/msw/private.h"
+#if defined(__WXWINCE__) && !defined(__HANDHELDPC__)
+ #include <ole2.h>
+ #include <shellapi.h>
+ #if _WIN32_WCE < 400
+ #include <aygshell.h>
+ #endif
+#endif
+
// include <commctrl.h> "properly"
#include "wx/msw/wrapcctl.h"
// ----------------------------------------------------------------------------
// We have to handle both fooW and fooA notifications in several cases
-// because of broken commctl.dll and/or unicows.dll. This class is used to
+// because of broken comctl32.dll and/or unicows.dll. This class is used to
// convert LV_ITEMA and LV_ITEMW to LV_ITEM (which is either LV_ITEMA or
// LV_ITEMW depending on wxUSE_UNICODE setting), so that it can be processed
// by wxConvertToMSWListItem().
+#if wxUSE_UNICODE
+ #define LV_ITEM_NATIVE LV_ITEMW
+ #define LV_ITEM_OTHER LV_ITEMA
+
+ #define LV_CONV_TO_WX cMB2WX
+ #define LV_CONV_BUF wxMB2WXbuf
+#else // ANSI
+ #define LV_ITEM_NATIVE LV_ITEMA
+ #define LV_ITEM_OTHER LV_ITEMW
+
+ #define LV_CONV_TO_WX cWC2WX
+ #define LV_CONV_BUF wxWC2WXbuf
+#endif // Unicode/ANSI
+
class wxLV_ITEM
{
public:
- ~wxLV_ITEM() { delete m_buf; }
- operator LV_ITEM&() const { return *m_item; }
+ // default ctor, use Init() later
+ wxLV_ITEM() { m_buf = NULL; m_pItem = NULL; }
-#if wxUSE_UNICODE
- wxLV_ITEM(LV_ITEMW &item) : m_buf(NULL), m_item(&item) {}
- wxLV_ITEM(LV_ITEMA &item)
+ // init without conversion
+ void Init(LV_ITEM_NATIVE& item)
{
- m_item = new LV_ITEM((LV_ITEM&)item);
- if ( (item.mask & LVIF_TEXT) && item.pszText )
- {
- m_buf = new wxMB2WXbuf(wxConvLocal.cMB2WX(item.pszText));
- m_item->pszText = (wxChar*)m_buf->data();
- }
- else
- m_buf = NULL;
+ wxASSERT_MSG( !m_pItem, _T("Init() called twice?") );
+
+ m_pItem = &item;
}
-private:
- wxMB2WXbuf *m_buf;
-#else // !wxUSE_UNICODE
- wxLV_ITEM(LV_ITEMW &item)
+ // init with conversion
+ void Init(LV_ITEM_OTHER& item)
{
- m_item = new LV_ITEM((LV_ITEM&)item);
+ // avoid unnecessary dynamic memory allocation, jjust make m_pItem
+ // point to our own m_item
+
+ // memcpy() can't work if the struct sizes are different
+ wxCOMPILE_TIME_ASSERT( sizeof(LV_ITEM_OTHER) == sizeof(LV_ITEM_NATIVE),
+ CodeCantWorkIfDiffSizes);
+
+ memcpy(&m_item, &item, sizeof(LV_ITEM_NATIVE));
- // the code below doesn't compile without wxUSE_WCHAR_T and as I don't
- // know if it's useful to have it at all (do we ever get Unicode
- // notifications in ANSI mode? I don't think so...) I'm not going to
- // write alternative implementation right now
- //
- // but if it is indeed used, we should simply directly use
- // ::WideCharToMultiByte() here
-#if wxUSE_WCHAR_T
+ // convert text from ANSI to Unicod if necessary
if ( (item.mask & LVIF_TEXT) && item.pszText )
{
- m_buf = new wxWC2WXbuf(wxConvLocal.cWC2WX(item.pszText));
- m_item->pszText = (wxChar*)m_buf->data();
+ m_buf = new LV_CONV_BUF(wxConvLocal.LV_CONV_TO_WX(item.pszText));
+ m_item.pszText = (wxChar *)m_buf->data();
}
- else
-#endif // wxUSE_WCHAR_T
- m_buf = NULL;
}
- wxLV_ITEM(LV_ITEMA &item) : m_buf(NULL), m_item(&item) {}
+
+ // ctor without conversion
+ wxLV_ITEM(LV_ITEM_NATIVE& item) : m_buf(NULL), m_pItem(&item) { }
+
+ // ctor with conversion
+ wxLV_ITEM(LV_ITEM_OTHER& item) : m_buf(NULL)
+ {
+ Init(item);
+ }
+
+ ~wxLV_ITEM() { delete m_buf; }
+
+ // conversion to the real LV_ITEM
+ operator LV_ITEM_NATIVE&() const { return *m_pItem; }
+
private:
- wxWC2WXbuf *m_buf;
-#endif // wxUSE_UNICODE/!wxUSE_UNICODE
+ LV_CONV_BUF *m_buf;
- LV_ITEM *m_item;
+ LV_ITEM_NATIVE *m_pItem;
+ LV_ITEM_NATIVE m_item;
DECLARE_NO_COPY_CLASS(wxLV_ITEM)
};
// Get the internal data structure
static wxListItemInternalData *wxGetInternalData(HWND hwnd, long itemId);
-static wxListItemInternalData *wxGetInternalData(wxListCtrl *ctl, long itemId);
+static wxListItemInternalData *wxGetInternalData(const wxListCtrl *ctl, long itemId);
static wxListItemAttr *wxGetInternalDataAttr(wxListCtrl *ctl, long itemId);
static void wxDeleteInternalData(wxListCtrl* ctl, long itemId);
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS)
+#if WXWIN_COMPATIBILITY_2_4
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO)
+#endif
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN)
wxFLAGS_MEMBER(wxBORDER_RAISED)
wxFLAGS_MEMBER(wxBORDER_STATIC)
wxFLAGS_MEMBER(wxBORDER_NONE)
-
+
// old style border flags
wxFLAGS_MEMBER(wxSIMPLE_BORDER)
wxFLAGS_MEMBER(wxSUNKEN_BORDER)
wxFLAGS_MEMBER(wxDOUBLE_BORDER)
wxFLAGS_MEMBER(wxRAISED_BORDER)
wxFLAGS_MEMBER(wxSTATIC_BORDER)
- wxFLAGS_MEMBER(wxNO_BORDER)
+ wxFLAGS_MEMBER(wxBORDER)
// standard window styles
wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
wxFLAGS_MEMBER(wxCLIP_CHILDREN)
wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
wxFLAGS_MEMBER(wxWANTS_CHARS)
- wxFLAGS_MEMBER(wxNO_FULL_REPAINT_ON_RESIZE)
+ wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
wxFLAGS_MEMBER(wxVSCROLL)
wxFLAGS_MEMBER(wxHSCROLL)
IMPLEMENT_DYNAMIC_CLASS_XTI(wxListCtrl, wxControl,"wx/listctrl.h")
wxBEGIN_PROPERTIES_TABLE(wxListCtrl)
- wxEVENT_PROPERTY( TextUpdated , wxEVT_COMMAND_TEXT_UPDATED , wxCommandEvent )
+ wxEVENT_PROPERTY( TextUpdated , wxEVT_COMMAND_TEXT_UPDATED , wxCommandEvent )
- wxPROPERTY_FLAGS( WindowStyle , wxListCtrlStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
+ wxPROPERTY_FLAGS( WindowStyle , wxListCtrlStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
wxEND_PROPERTIES_TABLE()
wxBEGIN_HANDLERS_TABLE(wxListCtrl)
wxEND_HANDLERS_TABLE()
-wxCONSTRUCTOR_5( wxListCtrl , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle )
+wxCONSTRUCTOR_5( wxListCtrl , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle )
/*
TODO : Expose more information of a list's layout etc. via appropriate objects (à la NotebookPageInfo)
m_imageListNormal = NULL;
m_imageListSmall = NULL;
m_imageListState = NULL;
- m_ownsImageListNormal = m_ownsImageListSmall = m_ownsImageListState = FALSE;
- m_baseStyle = 0;
+ m_ownsImageListNormal = m_ownsImageListSmall = m_ownsImageListState = false;
m_colCount = 0;
m_count = 0;
- m_ignoreChangeMessages = FALSE;
+ m_ignoreChangeMessages = false;
m_textCtrl = NULL;
- m_AnyInternalData = FALSE;
- m_hasAnyAttr = FALSE;
+ m_AnyInternalData = false;
+ m_hasAnyAttr = false;
}
bool wxListCtrl::Create(wxWindow *parent,
const wxPoint& pos,
const wxSize& size,
long style,
- const wxValidator& wxVALIDATOR_PARAM(validator),
+ const wxValidator& validator,
const wxString& name)
{
-#if wxUSE_VALIDATORS
- SetValidator(validator);
-#endif // wxUSE_VALIDATORS
+ if ( !CreateControl(parent, id, pos, size, style, validator, name) )
+ return false;
- SetName(name);
+ if ( !MSWCreateControl(WC_LISTVIEW, wxEmptyString, pos, size) )
+ return false;
- int x = pos.x;
- int y = pos.y;
- int width = size.x;
- int height = size.y;
+ // explicitly say that we want to use Unicode because otherwise we get ANSI
+ // versions of _some_ messages (notably LVN_GETDISPINFOA) in MSLU build
+ wxSetCCUnicodeFormat(GetHwnd());
- m_windowStyle = style;
+ // for comctl32.dll v 4.70+ we want to have this attribute because it's
+ // prettier (and also because wxGTK does it like this)
+ if ( InReportView() && wxTheApp->GetComCtl32Version() >= 470 )
+ {
+ ::SendMessage(GetHwnd(), LVM_SETEXTENDEDLISTVIEWSTYLE,
+ 0, LVS_EX_FULLROWSELECT);
+ }
- SetParent(parent);
+ return true;
+}
- if (width <= 0)
- width = 100;
- if (height <= 0)
- height = 30;
- if (x < 0)
- x = 0;
- if (y < 0)
- y = 0;
+WXDWORD wxListCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
+{
+ WXDWORD wstyle = wxControl::MSWGetStyle(style, exstyle);
- m_windowId = (id == -1) ? NewControlId() : id;
+ wstyle |= LVS_SHAREIMAGELISTS | LVS_SHOWSELALWAYS;
- DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP |
- LVS_SHAREIMAGELISTS | LVS_SHOWSELALWAYS;
+#ifdef __WXDEBUG__
+ size_t nModes = 0;
- m_baseStyle = wstyle;
+ #define MAP_MODE_STYLE(wx, ms) \
+ if ( style & (wx) ) { wstyle |= (ms); nModes++; }
+#else // !__WXDEBUG__
+ #define MAP_MODE_STYLE(wx, ms) \
+ if ( style & (wx) ) wstyle |= (ms);
+#endif // __WXDEBUG__
- if ( !DoCreateControl(x, y, width, height) )
- return FALSE;
+ MAP_MODE_STYLE(wxLC_ICON, LVS_ICON)
+ MAP_MODE_STYLE(wxLC_SMALL_ICON, LVS_SMALLICON)
+ MAP_MODE_STYLE(wxLC_LIST, LVS_LIST)
+ MAP_MODE_STYLE(wxLC_REPORT, LVS_REPORT)
- if (parent)
- parent->AddChild(this);
+ wxASSERT_MSG( nModes == 1,
+ _T("wxListCtrl style should have exactly one mode bit set") );
- return TRUE;
-}
+#undef MAP_MODE_STYLE
-bool wxListCtrl::DoCreateControl(int x, int y, int w, int h)
-{
- DWORD wstyle = m_baseStyle;
+ if ( style & wxLC_ALIGN_LEFT )
+ wstyle |= LVS_ALIGNLEFT;
- WXDWORD exStyle = 0;
- WXDWORD standardStyle = MSWGetStyle(GetWindowStyle(), & exStyle) ;
+ if ( style & wxLC_ALIGN_TOP )
+ wstyle |= LVS_ALIGNTOP;
- long oldStyle = 0; // Dummy
- wstyle |= ConvertToMSWStyle(oldStyle, m_windowStyle);
- wstyle |= standardStyle;
+ if ( style & wxLC_AUTOARRANGE )
+ wstyle |= LVS_AUTOARRANGE;
- // Create the ListView control.
- m_hWnd = (WXHWND)CreateWindowEx(exStyle,
- WC_LISTVIEW,
- wxEmptyString,
- wstyle,
- x, y, w, h,
- GetWinHwnd(GetParent()),
- (HMENU)m_windowId,
- wxGetInstance(),
- NULL);
+ if ( style & wxLC_NO_SORT_HEADER )
+ wstyle |= LVS_NOSORTHEADER;
- if ( !m_hWnd )
- {
- wxLogError(_("Can't create list control window, check that comctl32.dll is installed."));
+ if ( style & wxLC_NO_HEADER )
+ wstyle |= LVS_NOCOLUMNHEADER;
- return FALSE;
- }
+ if ( style & wxLC_EDIT_LABELS )
+ wstyle |= LVS_EDITLABELS;
- // explicitly say that we want to use Unicode because otherwise we get ANSI
- // versions of _some_ messages (notably LVN_GETDISPINFOA) in MSLU build
-#if wxUSE_UNICODE
- ::SendMessage(GetHwnd(), LVM_SETUNICODEFORMAT, TRUE, 0);
-#endif
+ if ( style & wxLC_SINGLE_SEL )
+ wstyle |= LVS_SINGLESEL;
- // for comctl32.dll v 4.70+ we want to have this attribute because it's
- // prettier (and also because wxGTK does it like this)
- if ( (wstyle & LVS_REPORT) && wxTheApp->GetComCtl32Version() >= 470 )
+ if ( style & wxLC_SORT_ASCENDING )
{
- ::SendMessage(GetHwnd(), LVM_SETEXTENDEDLISTVIEWSTYLE,
- 0, LVS_EX_FULLROWSELECT);
+ wstyle |= LVS_SORTASCENDING;
+
+ wxASSERT_MSG( !(style & wxLC_SORT_DESCENDING),
+ _T("can't sort in ascending and descending orders at once") );
}
+ else if ( style & wxLC_SORT_DESCENDING )
+ wstyle |= LVS_SORTDESCENDING;
- SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
- SetForegroundColour(GetParent()->GetForegroundColour());
+#if !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) )
+ if ( style & wxLC_VIRTUAL )
+ {
+ int ver = wxTheApp->GetComCtl32Version();
+ if ( ver < 470 )
+ {
+ wxLogWarning(_("Please install a newer version of comctl32.dll\n(at least version 4.70 is required but you have %d.%02d)\nor this program won't operate correctly."),
+ ver / 100, ver % 100);
+ }
- SubclassWin(m_hWnd);
+ wstyle |= LVS_OWNERDATA;
+ }
+#endif // ancient cygwin
- return TRUE;
+ return wstyle;
}
void wxListCtrl::UpdateStyle()
{
- if ( GetHWND() )
+ if ( GetHwnd() )
{
// The new window view style
- long dummy;
- DWORD dwStyleNew = ConvertToMSWStyle(dummy, m_windowStyle);
- dwStyleNew |= m_baseStyle;
+ DWORD dwStyleNew = MSWGetStyle(m_windowStyle, NULL);
+
+ // some styles are not returned by MSWGetStyle()
+ if ( IsShown() )
+ dwStyleNew |= WS_VISIBLE;
// Get the current window style.
DWORD dwStyleOld = ::GetWindowLong(GetHwnd(), GWL_STYLE);
+ // we don't have wxVSCROLL style, but the list control may have it,
+ // don't change it then
+ dwStyleNew |= dwStyleOld & (WS_HSCROLL | WS_VSCROLL);
+
// Only set the window style if the view bits have changed.
if ( dwStyleOld != dwStyleNew )
{
if (m_AnyInternalData)
{
int n = GetItemCount();
- int i = 0;
- m_ignoreChangeMessages = TRUE;
- for (i = 0; i < n; i++)
+ m_ignoreChangeMessages = true;
+ for (int i = 0; i < n; i++)
wxDeleteInternalData(this, i);
- m_ignoreChangeMessages = FALSE;
+ m_ignoreChangeMessages = false;
- m_AnyInternalData = FALSE;
+ m_AnyInternalData = false;
}
}
m_textCtrl = NULL;
}
- if (m_ownsImageListNormal) delete m_imageListNormal;
- if (m_ownsImageListSmall) delete m_imageListSmall;
- if (m_ownsImageListState) delete m_imageListState;
+ if (m_ownsImageListNormal)
+ delete m_imageListNormal;
+ if (m_ownsImageListSmall)
+ delete m_imageListSmall;
+ if (m_ownsImageListState)
+ delete m_imageListState;
}
// ----------------------------------------------------------------------------
flag = flag & ~wxLC_MASK_SORT;
}
- if ( flag & style )
- {
- if ( !add )
- flag -= style;
- }
+ if ( add )
+ flag |= style;
else
- {
- if ( add )
- {
- flag |= style;
- }
- }
+ flag &= ~style;
- m_windowStyle = flag;
-
- UpdateStyle();
+ SetWindowStyleFlag(flag);
}
// Set the whole window style
void wxListCtrl::SetWindowStyleFlag(long flag)
{
- m_windowStyle = flag;
-
- UpdateStyle();
-}
-
-// Can be just a single style, or a bitlist
-long wxListCtrl::ConvertToMSWStyle(long& oldStyle, long style) const
-{
- long wstyle = 0;
- if ( style & wxLC_ICON )
+ if ( flag != m_windowStyle )
{
- if ( (oldStyle & LVS_TYPEMASK) == LVS_SMALLICON )
- oldStyle -= LVS_SMALLICON;
- if ( (oldStyle & LVS_TYPEMASK) == LVS_REPORT )
- oldStyle -= LVS_REPORT;
- if ( (oldStyle & LVS_TYPEMASK) == LVS_LIST )
- oldStyle -= LVS_LIST;
- wstyle |= LVS_ICON;
- }
-
- if ( style & wxLC_SMALL_ICON )
- {
- if ( (oldStyle & LVS_TYPEMASK) == LVS_ICON )
- oldStyle -= LVS_ICON;
- if ( (oldStyle & LVS_TYPEMASK) == LVS_REPORT )
- oldStyle -= LVS_REPORT;
- if ( (oldStyle & LVS_TYPEMASK) == LVS_LIST )
- oldStyle -= LVS_LIST;
- wstyle |= LVS_SMALLICON;
- }
-
- if ( style & wxLC_LIST )
- {
- if ( (oldStyle & LVS_TYPEMASK) == LVS_ICON )
- oldStyle -= LVS_ICON;
- if ( (oldStyle & LVS_TYPEMASK) == LVS_REPORT )
- oldStyle -= LVS_REPORT;
- if ( (oldStyle & LVS_TYPEMASK) == LVS_SMALLICON )
- oldStyle -= LVS_SMALLICON;
- wstyle |= LVS_LIST;
- }
-
- if ( style & wxLC_REPORT )
- {
- if ( (oldStyle & LVS_TYPEMASK) == LVS_ICON )
- oldStyle -= LVS_ICON;
- if ( (oldStyle & LVS_TYPEMASK) == LVS_LIST )
- oldStyle -= LVS_LIST;
- if ( (oldStyle & LVS_TYPEMASK) == LVS_SMALLICON )
- oldStyle -= LVS_SMALLICON;
+ m_windowStyle = flag;
- wstyle |= LVS_REPORT;
- }
+ UpdateStyle();
- if ( style & wxLC_ALIGN_LEFT )
- {
- if ( oldStyle & LVS_ALIGNTOP )
- oldStyle -= LVS_ALIGNTOP;
- wstyle |= LVS_ALIGNLEFT;
+ Refresh();
}
-
- if ( style & wxLC_ALIGN_TOP )
- {
- if ( oldStyle & LVS_ALIGNLEFT )
- oldStyle -= LVS_ALIGNLEFT;
- wstyle |= LVS_ALIGNTOP;
- }
-
- if ( style & wxLC_AUTOARRANGE )
- wstyle |= LVS_AUTOARRANGE;
-
- if ( style & wxLC_NO_SORT_HEADER )
- wstyle |= LVS_NOSORTHEADER;
-
- if ( style & wxLC_NO_HEADER )
- wstyle |= LVS_NOCOLUMNHEADER;
-
- if ( style & wxLC_EDIT_LABELS )
- wstyle |= LVS_EDITLABELS;
-
- if ( style & wxLC_SINGLE_SEL )
- wstyle |= LVS_SINGLESEL;
-
- if ( style & wxLC_SORT_ASCENDING )
- {
- if ( oldStyle & LVS_SORTDESCENDING )
- oldStyle -= LVS_SORTDESCENDING;
- wstyle |= LVS_SORTASCENDING;
- }
-
- if ( style & wxLC_SORT_DESCENDING )
- {
- if ( oldStyle & LVS_SORTASCENDING )
- oldStyle -= LVS_SORTASCENDING;
- wstyle |= LVS_SORTDESCENDING;
- }
-
-#if !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) )
- if ( style & wxLC_VIRTUAL )
- {
- int ver = wxTheApp->GetComCtl32Version();
- if ( ver < 470 )
- {
- wxLogWarning(_("Please install a newer version of comctl32.dll\n(at least version 4.70 is required but you have %d.%02d)\nor this program won't operate correctly."),
- ver / 100, ver % 100);
- }
-
- wstyle |= LVS_OWNERDATA;
- }
-#endif
-
- return wstyle;
}
// ----------------------------------------------------------------------------
// accessors
// ----------------------------------------------------------------------------
+/* static */ wxVisualAttributes
+wxListCtrl::GetClassDefaultAttributes(wxWindowVariant variant)
+{
+ wxVisualAttributes attrs = GetCompositeControlsDefaultAttributes(variant);
+
+ // common controls have their own default font
+ attrs.font = wxGetCCDefaultFont();
+
+ return attrs;
+}
+
// Sets the foreground, i.e. text, colour
bool wxListCtrl::SetForegroundColour(const wxColour& col)
{
if ( !wxWindow::SetForegroundColour(col) )
- return FALSE;
+ return false;
ListView_SetTextColor(GetHwnd(), wxColourToRGB(col));
- return TRUE;
+ return true;
}
// Sets the background colour
bool wxListCtrl::SetBackgroundColour(const wxColour& col)
{
if ( !wxWindow::SetBackgroundColour(col) )
- return FALSE;
+ return false;
// we set the same colour for both the "empty" background and the items
// background
ListView_SetBkColor(GetHwnd(), color);
ListView_SetTextBkColor(GetHwnd(), color);
- return TRUE;
+ return true;
}
// Gets information about this column
// Sets the column width
bool wxListCtrl::SetColumnWidth(int col, int width)
{
- int col2 = col;
if ( m_windowStyle & wxLC_LIST )
- col2 = -1;
+ col = 0;
- int width2 = width;
- if ( width2 == wxLIST_AUTOSIZE)
- width2 = LVSCW_AUTOSIZE;
- else if ( width2 == wxLIST_AUTOSIZE_USEHEADER)
- width2 = LVSCW_AUTOSIZE_USEHEADER;
+ if ( width == wxLIST_AUTOSIZE)
+ width = LVSCW_AUTOSIZE;
+ else if ( width == wxLIST_AUTOSIZE_USEHEADER)
+ width = LVSCW_AUTOSIZE_USEHEADER;
- return ListView_SetColumnWidth(GetHwnd(), col2, width2) != 0;
+ return ListView_SetColumnWidth(GetHwnd(), col, width) != 0;
}
// Gets the number of items that can fit vertically in the
if ( info.m_mask & wxLIST_MASK_STATE )
{
lvItem.mask |= LVIF_STATE;
- // the other bits are hardly interesting anyhow
- lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
+ wxConvertToMSWFlags(0, info.m_stateMask, lvItem);
}
bool success = ListView_GetItem((HWND)GetHWND(), &lvItem) != 0;
if (! data)
{
// need to set it
- m_AnyInternalData = TRUE;
+ m_AnyInternalData = true;
data = new wxListItemInternalData();
item.lParam = (LPARAM) data;
item.mask |= LVIF_PARAM;
{
wxLogDebug(_T("ListView_SetItem() failed"));
- return FALSE;
+ return false;
}
}
// check whether it has any custom attributes
if ( info.HasAttributes() )
{
- m_hasAnyAttr = TRUE;
+ m_hasAnyAttr = true;
// if the colour has changed, we must redraw the item
- updateNow = TRUE;
+ updateNow = true;
}
if ( updateNow )
RefreshItem(item.iItem);
}
- return TRUE;
+ return true;
}
long wxListCtrl::SetItem(long index, int col, const wxString& label, int imageId)
{
wxLogLastError(_T("ListView_SetItemState"));
- return FALSE;
+ return false;
}
if ( focusOld != -1 )
}
}
- return TRUE;
+ return true;
}
// Sets the item image
}
// Gets the item data
-long wxListCtrl::GetItemData(long item) const
+wxUIntPtr wxListCtrl::GetItemData(long item) const
{
wxListItem info;
wxColour wxListCtrl::GetItemTextColour( long item ) const
{
- wxListItem info;
- info.m_itemId = item;
- GetItem( info );
- return info.GetTextColour();
+ wxColour col;
+ wxListItemInternalData *data = wxGetInternalData(this, item);
+ if ( data && data->attr )
+ col = data->attr->GetTextColour();
+
+ return col;
}
void wxListCtrl::SetItemBackgroundColour( long item, const wxColour &col )
wxColour wxListCtrl::GetItemBackgroundColour( long item ) const
{
- wxListItem info;
- info.m_itemId = item;
- GetItem( info );
- return info.GetBackgroundColour();
+ wxColour col;
+ wxListItemInternalData *data = wxGetInternalData(this, item);
+ if ( data && data->attr )
+ col = data->attr->GetBackgroundColour();
+
+ return col;
}
// Gets the number of selected items in the list control
flags = LVSIL_NORMAL;
if (m_ownsImageListNormal) delete m_imageListNormal;
m_imageListNormal = imageList;
- m_ownsImageListNormal = FALSE;
+ m_ownsImageListNormal = false;
}
else if ( which == wxIMAGE_LIST_SMALL )
{
flags = LVSIL_SMALL;
if (m_ownsImageListSmall) delete m_imageListSmall;
m_imageListSmall = imageList;
- m_ownsImageListSmall = FALSE;
+ m_ownsImageListSmall = false;
}
else if ( which == wxIMAGE_LIST_STATE )
{
flags = LVSIL_STATE;
if (m_ownsImageListState) delete m_imageListState;
m_imageListState = imageList;
- m_ownsImageListState = FALSE;
+ m_ownsImageListState = false;
}
ListView_SetImageList(GetHwnd(), (HIMAGELIST) imageList ? imageList->GetHIMAGELIST() : 0, flags);
}
{
SetImageList(imageList, which);
if ( which == wxIMAGE_LIST_NORMAL )
- m_ownsImageListNormal = TRUE;
+ m_ownsImageListNormal = true;
else if ( which == wxIMAGE_LIST_SMALL )
- m_ownsImageListSmall = TRUE;
+ m_ownsImageListSmall = true;
else if ( which == wxIMAGE_LIST_STATE )
- m_ownsImageListState = TRUE;
+ m_ownsImageListState = true;
}
// ----------------------------------------------------------------------------
if ( !ListView_DeleteItem(GetHwnd(), (int) item) )
{
wxLogLastError(_T("ListView_DeleteItem"));
- return FALSE;
+ return false;
}
- m_count -= 1;
+ m_count--;
wxASSERT_MSG( m_count == ListView_GetItemCount(GetHwnd()),
wxT("m_count should match ListView_GetItemCount"));
RefreshRect(rectWin);
}
- return TRUE;
+ return true;
}
// Deletes all items
bool wxListCtrl::DeleteAllItems()
{
- FreeAllInternalData();
return ListView_DeleteAllItems(GetHwnd()) != 0;
}
{
wxLogLastError(wxT("ListView_DeleteColumn"));
- return FALSE;
+ return false;
}
m_colCount--;
wxASSERT_MSG( m_colCount == 0, wxT("no columns should be left") );
- return TRUE;
+ return true;
}
// Deletes a column
{
wxFAIL_MSG( _T("not implemented") );
- return FALSE;
+ return false;
}
// Ensures this item is visible
bool wxListCtrl::EnsureVisible(long item)
{
- return ListView_EnsureVisible(GetHwnd(), (int) item, FALSE) != 0;
+ return ListView_EnsureVisible(GetHwnd(), (int) item, FALSE) != FALSE;
}
// Find an item whose label matches this string, starting from the item after 'start'
// NOTE : Lindsay Mathieson - 14-July-2002
// No longer use ListView_FindItem as the data attribute is now stored
// in a wxListItemInternalData structure refernced by the actual lParam
-long wxListCtrl::FindItem(long start, long data)
+long wxListCtrl::FindItem(long start, wxUIntPtr data)
{
long idx = start + 1;
long count = GetItemCount();
ListView_HitTest(GetHwnd(), & hitTestInfo);
flags = 0;
+
if ( hitTestInfo.flags & LVHT_ABOVE )
flags |= wxLIST_HITTEST_ABOVE;
if ( hitTestInfo.flags & LVHT_BELOW )
flags |= wxLIST_HITTEST_BELOW;
- if ( hitTestInfo.flags & LVHT_NOWHERE )
- flags |= wxLIST_HITTEST_NOWHERE;
- if ( hitTestInfo.flags & LVHT_ONITEMICON )
- flags |= wxLIST_HITTEST_ONITEMICON;
- if ( hitTestInfo.flags & LVHT_ONITEMLABEL )
- flags |= wxLIST_HITTEST_ONITEMLABEL;
- if ( hitTestInfo.flags & LVHT_ONITEMSTATEICON )
- flags |= wxLIST_HITTEST_ONITEMSTATEICON;
if ( hitTestInfo.flags & LVHT_TOLEFT )
flags |= wxLIST_HITTEST_TOLEFT;
if ( hitTestInfo.flags & LVHT_TORIGHT )
flags |= wxLIST_HITTEST_TORIGHT;
+ if ( hitTestInfo.flags & LVHT_NOWHERE )
+ flags |= wxLIST_HITTEST_NOWHERE;
+
+ // note a bug or at least a very strange feature of comtl32.dll (tested
+ // with version 4.0 under Win95 and 6.0 under Win 2003): if you click to
+ // the right of the item label, ListView_HitTest() returns a combination of
+ // LVHT_ONITEMICON, LVHT_ONITEMLABEL and LVHT_ONITEMSTATEICON -- filter out
+ // the bits which don't make sense
+ if ( hitTestInfo.flags & LVHT_ONITEMLABEL )
+ {
+ flags |= wxLIST_HITTEST_ONITEMLABEL;
+
+ // do not translate LVHT_ONITEMICON here, as per above
+ }
+ else
+ {
+ if ( hitTestInfo.flags & LVHT_ONITEMICON )
+ flags |= wxLIST_HITTEST_ONITEMICON;
+ if ( hitTestInfo.flags & LVHT_ONITEMSTATEICON )
+ flags |= wxLIST_HITTEST_ONITEMSTATEICON;
+ }
+
return (long) hitTestInfo.iItem;
}
bool needInternalData = ((info.m_mask & wxLIST_MASK_DATA) || info.HasAttributes());
if (needInternalData)
{
- m_AnyInternalData = TRUE;
+ m_AnyInternalData = true;
item.mask |= LVIF_PARAM;
// internal stucture that manages data
{
// take copy of attributes
data->attr = new wxListItemAttr(*info.GetAttributes());
+
+ // and remember that we have some now...
+ m_hasAnyAttr = true;
}
};
{
wxLogDebug(_T("ListView_Scroll(%d, %d) failed"), dx, dy);
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
// Sort items.
{
wxLogDebug(_T("ListView_SortItems() failed"));
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, id);
event.SetEventObject( this );
ProcessCommand(event);
- return TRUE;
+ return true;
}
else if (cmd == EN_KILLFOCUS)
{
wxCommandEvent event(wxEVT_KILL_FOCUS, id);
event.SetEventObject( this );
ProcessCommand(event);
- return TRUE;
+ return true;
}
else
- return FALSE;
+ return false;
}
bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
event.m_col = nmHDR->iItem;
break;
+#if defined(__WXWINCE__) && !defined(__HANDHELDPC__) && _WIN32_WCE < 400
+ case GN_CONTEXTMENU:
+#endif //__WXWINCE__
case NM_RCLICK:
{
eventType = wxEVT_COMMAND_LIST_COL_RIGHT_CLICK;
// where did the click occur?
POINT ptClick;
+#if defined(__WXWINCE__) && !defined(__HANDHELDPC__) && _WIN32_WCE < 400
+ if(nmhdr->code == GN_CONTEXTMENU) {
+ ptClick = ((NMRGINFO*)nmhdr)->ptAction;
+ } else
+#endif //__WXWINCE__
if ( !::GetCursorPos(&ptClick) )
{
wxLogLastError(_T("GetCursorPos"));
}
- if ( !::ScreenToClient(hwndHdr, &ptClick) )
+ if ( !::ScreenToClient(GetHwnd(), &ptClick) )
{
wxLogLastError(_T("ScreenToClient(listctrl header)"));
}
break;
case HDN_GETDISPINFOW:
- {
- LPNMHDDISPINFOW info = (LPNMHDDISPINFOW) lParam;
- // This is a fix for a strange bug under XP.
- // Normally, info->iItem is a valid index, but
- // sometimes this is a silly (large) number
- // and when we return FALSE via wxControl::MSWOnNotify
- // to indicate that it hasn't yet been processed,
- // there's a GPF in Windows.
- // By returning TRUE here, we avoid further processing
- // of this strange message.
- if ( info->iItem >= GetColumnCount() )
- return TRUE;
- }
- // fall through
+ // letting Windows XP handle this message results in mysterious
+ // crashes in comctl32.dll seemingly because of bad message
+ // parameters
+ //
+ // I have no idea what is the real cause of the bug (which is,
+ // just to make things interesting, is impossible to reproduce
+ // reliably) but ignoring all these messages does fix it and
+ // doesn't seem to have any negative consequences
+ return true;
default:
return wxControl::MSWOnNotify(idCtrl, lParam, result);
// ignored for efficiency. It is done here because the internal data is in the
// process of being deleted so we don't want to try and access it below.
if ( m_ignoreChangeMessages &&
- ( (nmLV->hdr.code == LVN_ITEMCHANGED) || (nmLV->hdr.code == LVN_ITEMCHANGING)))
+ ( (nmLV->hdr.code == LVN_ITEMCHANGED) ||
+ (nmLV->hdr.code == LVN_ITEMCHANGING)) )
{
- return TRUE;
+ return true;
}
break;
// NB: we have to handle both *A and *W versions here because some
- // versions of comctl32.dll send ANSI message to an Unicode app
+ // versions of comctl32.dll send ANSI messages even to the
+ // Unicode windows
case LVN_BEGINLABELEDITA:
- {
- eventType = wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT;
- wxLV_ITEM item(((LV_DISPINFOA *)lParam)->item);
- wxConvertFromMSWListItem(GetHwnd(), event.m_item, item);
- event.m_itemIndex = event.m_item.m_itemId;
- }
- break;
case LVN_BEGINLABELEDITW:
{
+ wxLV_ITEM item;
+ if ( nmhdr->code == LVN_BEGINLABELEDITA )
+ {
+ item.Init(((LV_DISPINFOA *)lParam)->item);
+ }
+ else // LVN_BEGINLABELEDITW
+ {
+ item.Init(((LV_DISPINFOW *)lParam)->item);
+ }
+
eventType = wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT;
- wxLV_ITEM item(((LV_DISPINFOW *)lParam)->item);
wxConvertFromMSWListItem(GetHwnd(), event.m_item, item);
event.m_itemIndex = event.m_item.m_itemId;
}
break;
case LVN_ENDLABELEDITA:
+ case LVN_ENDLABELEDITW:
{
- eventType = wxEVT_COMMAND_LIST_END_LABEL_EDIT;
- wxLV_ITEM item(((LV_DISPINFOA *)lParam)->item);
- wxConvertFromMSWListItem(NULL, event.m_item, item);
- if ( ((LV_ITEM)item).pszText == NULL ||
- ((LV_ITEM)item).iItem == -1 )
+ wxLV_ITEM item;
+ if ( nmhdr->code == LVN_ENDLABELEDITA )
{
- // don't keep a stale wxTextCtrl around
- if ( m_textCtrl )
- {
- // EDIT control will be deleted by the list control itself so
- // prevent us from deleting it as well
- m_textCtrl->UnsubclassWin();
- m_textCtrl->SetHWND(0);
- delete m_textCtrl;
- m_textCtrl = NULL;
- }
- return FALSE;
+ item.Init(((LV_DISPINFOA *)lParam)->item);
+ }
+ else // LVN_ENDLABELEDITW
+ {
+ item.Init(((LV_DISPINFOW *)lParam)->item);
}
- event.m_itemIndex = event.m_item.m_itemId;
- }
- break;
- case LVN_ENDLABELEDITW:
- {
- eventType = wxEVT_COMMAND_LIST_END_LABEL_EDIT;
- wxLV_ITEM item(((LV_DISPINFOW *)lParam)->item);
- wxConvertFromMSWListItem(NULL, event.m_item, item);
- if ( ((LV_ITEM)item).pszText == NULL ||
- ((LV_ITEM)item).iItem == -1 )
+ // was editing cancelled?
+ const LV_ITEM& lvi = (LV_ITEM)item;
+ if ( !lvi.pszText || lvi.iItem == -1 )
{
// don't keep a stale wxTextCtrl around
if ( m_textCtrl )
delete m_textCtrl;
m_textCtrl = NULL;
}
- return FALSE;
+
+ event.SetEditCanceled(true);
}
+ eventType = wxEVT_COMMAND_LIST_END_LABEL_EDIT;
+ wxConvertFromMSWListItem(NULL, event.m_item, item);
event.m_itemIndex = event.m_item.m_itemId;
}
break;
break;
case LVN_DELETEALLITEMS:
- m_count = 0;
eventType = wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS;
event.m_itemIndex = -1;
break;
case LVN_DELETEITEM:
- if (m_count == 0)
- // this should be prevented by the post-processing code below,
- // but "just in case"
- return FALSE;
+ if ( m_count == 0 )
+ {
+ // this should be prevented by the post-processing code
+ // below, but "just in case"
+ return false;
+ }
eventType = wxEVT_COMMAND_LIST_DELETE_ITEM;
event.m_itemIndex = iItem;
wxDeleteInternalData(this, iItem);
break;
+#if WXWIN_COMPATIBILITY_2_4
case LVN_SETDISPINFO:
{
eventType = wxEVT_COMMAND_LIST_SET_INFO;
wxConvertFromMSWListItem(GetHwnd(), event.m_item, info->item);
}
break;
+#endif
case LVN_INSERTITEM:
eventType = wxEVT_COMMAND_LIST_INSERT_ITEM;
case LVN_ITEMCHANGED:
// we translate this catch all message into more interesting
- // (and more easy to process) wxWindows events
+ // (and more easy to process) wxWidgets events
// first of all, we deal with the state change events only and
// only for valid items (item == -1 for the virtual list
if ( eventType == wxEVT_NULL )
{
// not an interesting event for us
- return FALSE;
+ return false;
}
break;
// anything else
if ( wxControl::MSWOnNotify(idCtrl, lParam, result) )
{
- return TRUE;
+ return true;
}
// else translate it into wxEVT_COMMAND_LIST_ITEM_ACTIVATED event
if ( iItem == -1 )
{
// not on item
- return FALSE;
+ return false;
}
eventType = wxEVT_COMMAND_LIST_ITEM_ACTIVATED;
event.m_item.m_data = GetItemData(iItem);
break;
+#if defined(__WXWINCE__) && !defined(__HANDHELDPC__) && _WIN32_WCE < 400
+ case GN_CONTEXTMENU:
+#endif //__WXWINCE__
case NM_RCLICK:
// if the user processes it in wxEVT_COMMAND_RIGHT_CLICK(),
// don't do anything else
if ( wxControl::MSWOnNotify(idCtrl, lParam, result) )
{
- return TRUE;
+ return true;
}
// else translate it into wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK event
LV_HITTESTINFO lvhti;
wxZeroMemory(lvhti);
+#if defined(__WXWINCE__) && !defined(__HANDHELDPC__) && _WIN32_WCE < 400
+ if(nmhdr->code == GN_CONTEXTMENU) {
+ lvhti.pt = ((NMRGINFO*)nmhdr)->ptAction;
+ } else
+#endif //__WXWINCE__
::GetCursorPos(&(lvhti.pt));
::ScreenToClient(GetHwnd(),&(lvhti.pt));
if ( ListView_HitTest(GetHwnd(),&lvhti) != -1 )
case NM_CUSTOMDRAW:
*result = OnCustomDraw(lParam);
- return TRUE;
+ return true;
#endif // _WIN32_IE >= 0x300
case LVN_ODCACHEHINT:
// deleting an item, for items in invalid range -- filter
// this garbage out
if ( cacheHint->iFrom > cacheHint->iTo )
- return FALSE;
+ return false;
event.m_oldItemIndex = cacheHint->iFrom;
wxASSERT_MSG( !(lvi.mask & LVIF_STATE),
_T("we don't support state callbacks yet!") );
- return TRUE;
+ return true;
}
// fall through
else
{
// where did this one come from?
- return FALSE;
+ return false;
}
// process the event
switch ( nmhdr->code )
{
case LVN_DELETEALLITEMS:
- // always return TRUE to suppress all additional LVN_DELETEITEM
+ // always return true to suppress all additional LVN_DELETEITEM
// notifications - this makes deleting all items from a list ctrl
// much faster
*result = TRUE;
- return TRUE;
+
+ // also, we may free all user data now (couldn't do it before as
+ // the user should have access to it in OnDeleteAllItems() handler)
+ FreeAllInternalData();
+
+ // the control is empty now, synchronize the cached number of items
+ // with the real one
+ m_count = 0;
+ return true;
case LVN_ENDLABELEDITA:
case LVN_ENDLABELEDITW:
m_textCtrl = NULL;
}
- return TRUE;
+ return true;
}
if ( processed )
// Reset the device origin since it may have been set
dc.SetDeviceOrigin(0, 0);
- bool drawHRules = ((GetWindowStyle() & wxLC_HRULES) != 0);
- bool drawVRules = ((GetWindowStyle() & wxLC_VRULES) != 0);
+ bool drawHRules = HasFlag(wxLC_HRULES);
+ bool drawVRules = HasFlag(wxLC_VRULES);
- if (!drawHRules && !drawVRules)
- return;
- if ((GetWindowStyle() & wxLC_REPORT) == 0)
+ if (!InReportView() || !drawHRules && !drawVRules)
return;
wxPen pen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT), 1, wxSOLID);
wxSize clientSize = GetClientSize();
wxRect itemRect;
- int cy=0;
int itemCount = GetItemCount();
int i;
{
if (GetItemRect(i, itemRect))
{
- cy = itemRect.GetTop();
+ int cy = itemRect.GetTop();
if (i != 0) // Don't draw the first one
{
dc.DrawLine(0, cy, clientSize.x, cy);
}
}
+WXLRESULT
+wxListCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
+{
+#ifdef WM_PRINT
+ if ( nMsg == WM_PRINT )
+ {
+ // we should bypass our own WM_PRINT handling as we don't handle
+ // PRF_CHILDREN flag, so leave it to the native control itself
+ return MSWDefWindowProc(nMsg, wParam, lParam);
+ }
+#endif // WM_PRINT
+
+ return wxControl::MSWWindowProc(nMsg, wParam, lParam);
+}
+
// ----------------------------------------------------------------------------
// virtual list controls
// ----------------------------------------------------------------------------
int wxListCtrl::OnGetItemImage(long WXUNUSED(item)) const
{
- // same as above
- wxFAIL_MSG( _T("wxListCtrl::OnGetItemImage not supposed to be called") );
-
+ wxCHECK_MSG(!GetImageList(wxIMAGE_LIST_SMALL),
+ -1,
+ wxT("List control has an image list, OnGetItemImage should be overridden."));
return -1;
}
{
wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
- if ( !::SendMessage(GetHwnd(), LVM_SETITEMCOUNT, (WPARAM)count, LVSICF_NOSCROLL) )
+ if ( !::SendMessage(GetHwnd(), LVM_SETITEMCOUNT, (WPARAM)count,
+ LVSICF_NOSCROLL | LVSICF_NOINVALIDATEALL) )
{
wxLogLastError(_T("ListView_SetItemCount"));
}
RefreshRect(rect);
}
+// ----------------------------------------------------------------------------
+// internal data stuff
+// ----------------------------------------------------------------------------
+
static wxListItemInternalData *wxGetInternalData(HWND hwnd, long itemId)
{
LV_ITEM it;
it.mask = LVIF_PARAM;
it.iItem = itemId;
- bool success = ListView_GetItem(hwnd, &it) != 0;
- if (success)
- return (wxListItemInternalData *) it.lParam;
- else
+ if ( !ListView_GetItem(hwnd, &it) )
return NULL;
+
+ return (wxListItemInternalData *) it.lParam;
};
-static wxListItemInternalData *wxGetInternalData(wxListCtrl *ctl, long itemId)
+static
+wxListItemInternalData *wxGetInternalData(const wxListCtrl *ctl, long itemId)
{
- return wxGetInternalData((HWND) ctl->GetHWND(), itemId);
+ return wxGetInternalData(GetHwndOf(ctl), itemId);
};
static wxListItemAttr *wxGetInternalDataAttr(wxListCtrl *ctl, long itemId)
{
wxListItemInternalData *data = wxGetInternalData(ctl, itemId);
- if (data)
- return data->attr;
- else
- return NULL;
+
+ return data ? data->attr : NULL;
};
static void wxDeleteInternalData(wxListCtrl* ctl, long itemId)
}
}
+// ----------------------------------------------------------------------------
+// wxWin <-> MSW items conversions
+// ----------------------------------------------------------------------------
+
static void wxConvertFromMSWListItem(HWND hwndListCtrl,
wxListItem& info,
LV_ITEM& lvItem)
long oldMask = lvItem.mask;
- bool needText = FALSE;
+ bool needText = false;
if (hwndListCtrl != 0)
{
if ( lvItem.mask & LVIF_TEXT )
- needText = FALSE;
+ needText = false;
else
- needText = TRUE;
+ needText = true;
if ( needText )
{
if (info.m_mask & wxLIST_MASK_TEXT)
{
lvItem.mask |= LVIF_TEXT;
- if ( ctrl->GetWindowStyleFlag() & wxLC_USER_TEXT )
+ if ( ctrl->HasFlag(wxLC_USER_TEXT) )
{
lvItem.pszText = LPSTR_TEXTCALLBACK;
}