Files
foobar2000-sdk/libPPUI/CListControlTruncationTooltipImpl.cpp
2021-12-14 00:28:25 -07:00

210 lines
6.0 KiB
C++

#include "stdafx.h"
#include "CListControl.h"
#include "PaintUtils.h"
LRESULT CListControlTruncationTooltipImpl::OnTTShow(int,LPNMHDR,BOOL&) {
SetTimer(KTooltipTimer,KTooltipTimerDelay);
return 0;
}
LRESULT CListControlTruncationTooltipImpl::OnTTPop(int,LPNMHDR,BOOL&) {
KillTimer(KTooltipTimer);
return 0;
}
LRESULT CListControlTruncationTooltipImpl::OnTTGetDispInfo(int,LPNMHDR p_hdr,BOOL&) {
LPNMTTDISPINFO info = (LPNMTTDISPINFO)p_hdr;
info->lpszText = const_cast<TCHAR*>(this->m_tooltipText.get_ptr());
info->hinst = 0;
info->uFlags = 0;
return 0;
}
LRESULT CListControlTruncationTooltipImpl::OnDestroyPassThru(UINT,WPARAM,LPARAM,BOOL& bHandled) {
if (m_tooltip.m_hWnd != NULL) m_tooltip.DestroyWindow();
KillTimer(KTooltipTimer);
bHandled = FALSE; return 0;
}
CListControlTruncationTooltipImpl::CListControlTruncationTooltipImpl()
: m_toolinfo()
, m_tooltipRect(0,0,0,0)
{
}
void CListControlTruncationTooltipImpl::TooltipRemove() {
m_tooltipRect = CRect(0,0,0,0);
if (m_tooltip.m_hWnd != NULL) {
m_tooltip.TrackActivate(&m_toolinfo,FALSE);
}
}
void CListControlTruncationTooltipImpl::TooltipRemoveCheck() {
CPoint pt = GetCursorPos();
if (ScreenToClient(&pt)) {
TooltipRemoveCheck( MAKELPARAM( pt.x, pt.y ) );
}
}
void CListControlTruncationTooltipImpl::TooltipRemoveCheck(LPARAM pos) {
if (!m_tooltipRect.IsRectEmpty()) {
CPoint pt(pos);
if (!GetClientRectHook().PtInRect(pt)) {
TooltipRemove();
} else {
ClientToScreen(&pt);
if (!m_tooltipRect.PtInRect(pt)) {
TooltipRemove();
}
}
}
}
LRESULT CListControlTruncationTooltipImpl::OnTimer(UINT,WPARAM wp,LPARAM,BOOL& bHandled) {
switch(wp) {
case KTooltipTimer:
TooltipRemoveCheck();
return 0;
default:
bHandled = FALSE;
return 0;
}
}
LRESULT CListControlTruncationTooltipImpl::OnMouseMovePassThru(UINT,WPARAM,LPARAM lp,BOOL& bHandled) {
TooltipRemoveCheck(lp);
{
TRACKMOUSEEVENT ev = {sizeof(ev)};
ev.dwFlags = TME_HOVER;
ev.hwndTrack = *this;
ev.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&ev);
}
bHandled = FALSE;
return 0;
}
bool CListControlTruncationTooltipImpl::IsRectPartiallyObscuredAbs(CRect const & r) const {
CRect cl = this->GetClientRectHook(); cl.OffsetRect( this->GetViewOffset() );
return r.right > cl.right || r.top < cl.top || r.bottom > cl.bottom;
}
bool CListControlTruncationTooltipImpl::IsRectFullyVisibleAbs(CRect const & r) {
CRect cl = this->GetClientRectHook(); cl.OffsetRect( this->GetViewOffset() );
return r.left >= cl.left && r.right <= cl.right && r.top >= cl.top && r.bottom <= cl.bottom;
}
bool CListControlTruncationTooltipImpl::GetTooltipData(CPoint pt, pfc::string_base & outText, CRect & outRC, CFontHandle & outFont) const {
t_size item; int group;
if (ItemFromPointAbs(pt, item)) {
const CRect itemRectAbs = this->GetItemRectAbs(item);
/*if (this->IsHeaderEnabled()) */{
t_uint32 cbase = 0;
auto orderArray = this->GetColumnOrderArray();
for (t_size _cwalk = 0; _cwalk < orderArray.size(); ++_cwalk) {
const t_size cwalk = orderArray[_cwalk];
//const TColumnRuntime & col = m_columns[cwalk];
const t_uint32 width = GetSubItemWidth(cwalk);
if ((t_uint32)pt.x < cbase + width) {
t_uint32 estWidth = GetOptimalSubItemWidthSimple(item, cwalk);
CRect rc = itemRectAbs; rc.left = cbase; rc.right = cbase + estWidth;
if (estWidth > width || (IsRectPartiallyObscuredAbs(rc) && rc.PtInRect(pt))) {
pfc::string_formatter label, ccTemp;
if (GetSubItemText(item, cwalk, label)) {
PaintUtils::TextOutColors_StripCodes(ccTemp, label);
outFont = GetFont(); outRC = rc; outText = ccTemp;
return true;
}
}
break;
}
cbase += width;
}
}
} else if (GroupHeaderFromPointAbs(pt, group)) {
CRect rc;
if (GetGroupHeaderRectAbs(group, rc) && rc.PtInRect(pt)) {
const t_uint32 estWidth = GetOptimalGroupHeaderWidth(group);
CRect rcText = rc; rcText.right = rcText.left + estWidth;
if (estWidth > (t_uint32)rc.Width() || (IsRectPartiallyObscuredAbs(rcText) && rcText.PtInRect(pt))) {
pfc::string_formatter label;
if (GetGroupHeaderText(group, label)) {
outFont = GetGroupHeaderFont(); outRC = rc; outText = label;
return true;
}
}
}
}
return false;
}
LRESULT CListControlTruncationTooltipImpl::OnHover(UINT,WPARAM wp,LPARAM lp,BOOL&) {
if (!m_tooltipRect.IsRectEmpty()) {
return 0;
}
if (wp & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON)) return 0;
const CPoint viewOffset = GetViewOffset();
CPoint pt ( lp ); pt += viewOffset;
CFontHandle font;
CRect rc;
pfc::string8 text;
if ( this->GetTooltipData(pt, text, rc, font) ) {
this->m_tooltipFont = font;
// Gets stuck if the text is very long!
if (text.length() < 4096) {
TooltipActivateAbs(text, rc);
}
}
return 0;
}
void CListControlTruncationTooltipImpl::TooltipActivateAbs(const char * label, const CRect & rect) {
CRect temp(rect);
temp.OffsetRect( - GetViewOffset() );
ClientToScreen(temp);
TooltipActivate(label,temp);
}
void CListControlTruncationTooltipImpl::TooltipActivate(const char * label, const CRect & rect) {
if (rect.IsRectEmpty()) return;
if (m_tooltip.m_hWnd == NULL) {
try {
InitTooltip();
} catch(std::exception const & e) {
(void) e;
// console::complain("Tooltip initialization failure", e);
return;
}
}
m_tooltipText.convert( EscapeTooltipText( label ) );
m_tooltipRect = rect;
TooltipUpdateFont();
m_tooltip.TrackPosition(rect.left,rect.top);
m_tooltip.TrackActivate(&m_toolinfo,TRUE);
}
void CListControlTruncationTooltipImpl::TooltipUpdateFont() {
if (m_tooltip.m_hWnd != NULL) {
if (m_tooltipFont) {
m_tooltip.SetFont(m_tooltipFont);
}
}
}
void CListControlTruncationTooltipImpl::InitTooltip() {
m_tooltipRect = CRect(0,0,0,0);
WIN32_OP( m_tooltip.Create(NULL,NULL,NULL,WS_POPUP,WS_EX_TRANSPARENT) );
m_toolinfo.cbSize = sizeof(m_toolinfo);
m_toolinfo.uFlags = TTF_TRACK | TTF_IDISHWND | TTF_ABSOLUTE | TTF_TRANSPARENT;
m_toolinfo.hwnd = *this;
m_toolinfo.uId = 0;
m_toolinfo.lpszText = LPSTR_TEXTCALLBACK;
m_toolinfo.hinst = GetThisModuleHandle();
WIN32_OP_D( m_tooltip.AddTool(&m_toolinfo) );
}