EG/pandatool/src/win-stats/winStatsLabel.cxx

391 lines
9.5 KiB
C++

/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file winStatsLabel.cxx
* @author drose
* @date 2004-01-07
*/
#include "winStatsLabel.h"
#include "winStatsMonitor.h"
#include "winStatsGraph.h"
#include "convert_srgb.h"
#include <commctrl.h>
int WinStatsLabel::_left_margin = 2;
int WinStatsLabel::_right_margin = 2;
int WinStatsLabel::_top_margin = 2;
int WinStatsLabel::_bottom_margin = 2;
bool WinStatsLabel::_window_class_registered = false;
const char * const WinStatsLabel::_window_class_name = "label";
/**
*
*/
WinStatsLabel::
WinStatsLabel(WinStatsMonitor *monitor, WinStatsGraph *graph,
int thread_index, int collector_index, bool use_fullname,
bool align_right) :
_monitor(monitor),
_graph(graph),
_thread_index(thread_index),
_collector_index(collector_index),
_align_right(align_right),
_window(0),
_tooltip_window(0)
{
update_text(use_fullname);
update_color();
_x = 0;
_y = 0;
_width = 0;
_height = 0;
_ideal_width = 0;
_highlight = false;
_mouse_within = false;
}
/**
*
*/
WinStatsLabel::
~WinStatsLabel() {
if (_window) {
if (_tooltip_window) {
DestroyWindow(_tooltip_window);
_tooltip_window = 0;
}
DestroyWindow(_window);
_window = 0;
}
DeleteObject(_bg_brush);
DeleteObject(_highlight_bg_brush);
}
/**
* Creates the actual window.
*/
void WinStatsLabel::
setup(HWND parent_window) {
if (_window) {
DestroyWindow(_window);
_window = 0;
}
create_window(parent_window);
HDC hdc = GetDC(_window);
HFONT hfnt = _monitor->get_font();
SelectObject(hdc, hfnt);
SIZE size;
GetTextExtentPoint32(hdc, _text.data(), _text.length(), &size);
_height = size.cy + _top_margin + _bottom_margin;
_ideal_width = size.cx + _left_margin + _right_margin;
ReleaseDC(_window, hdc);
}
/**
* Sets the position of the label on its parent. The position describes the
* lower-left corner of the rectangle, not the upper-left.
*/
void WinStatsLabel::
set_pos(int x, int y, int width) {
if (x != _x || y != _y || width != _width) {
_x = x;
_y = y;
_width = width;
SetWindowPos(_window, 0, x, y - _height, _width, _height,
SWP_NOZORDER | SWP_SHOWWINDOW);
}
}
/**
* Changes the Y attribute without updating the window.
*/
void WinStatsLabel::
set_y_noupdate(int y) {
_y = y;
}
/**
* Enables or disables the visual highlight for this label.
*/
void WinStatsLabel::
set_highlight(bool highlight) {
if (_highlight != highlight) {
_highlight = highlight;
InvalidateRect(_window, nullptr, TRUE);
}
}
/**
* Updates the colors.
*/
void WinStatsLabel::
update_color() {
if (_bg_brush != 0) {
DeleteObject(_bg_brush);
}
if (_highlight_bg_brush != 0) {
DeleteObject(_highlight_bg_brush);
}
LRGBColor rgb = _monitor->get_collector_color(_collector_index);
int r = (int)encode_sRGB_uchar((float)rgb[0]);
int g = (int)encode_sRGB_uchar((float)rgb[1]);
int b = (int)encode_sRGB_uchar((float)rgb[2]);
_bg_brush = CreateSolidBrush(RGB(r, g, b));
// Calculate the color when it is highlighted.
int hr = (int)encode_sRGB_uchar((float)rgb[0] * 0.75f);
int hg = (int)encode_sRGB_uchar((float)rgb[1] * 0.75f);
int hb = (int)encode_sRGB_uchar((float)rgb[2] * 0.75f);
_highlight_bg_brush = CreateSolidBrush(RGB(hr, hg, hb));
// Should our foreground be black or white?
double bright =
rgb[0] * 0.2126 +
rgb[1] * 0.7152 +
rgb[2] * 0.0722;
if (bright >= 0.5) {
_fg_color = RGB(0, 0, 0);
} else {
_fg_color = RGB(255, 255, 255);
}
if (bright * 0.75 >= 0.5) {
_highlight_fg_color = RGB(0, 0, 0);
} else {
_highlight_fg_color = RGB(255, 255, 255);
}
if (_window) {
InvalidateRect(_window, nullptr, TRUE);
}
}
/**
* Set to true if the full name of the collector should be shown.
*/
void WinStatsLabel::
update_text(bool use_fullname) {
const PStatClientData *client_data = _monitor->get_client_data();
_tooltip_text = client_data->get_collector_fullname(_collector_index);
if (use_fullname) {
_text = _tooltip_text;
} else {
_text = client_data->get_collector_name(_collector_index);
}
// Recalculate the dimensions.
if (_window) {
HDC hdc = GetDC(_window);
HFONT hfnt = _monitor->get_font();
SelectObject(hdc, hfnt);
SIZE size;
GetTextExtentPoint32(hdc, _text.data(), _text.length(), &size);
_height = size.cy + _top_margin + _bottom_margin;
_ideal_width = size.cx + _left_margin + _right_margin;
}
}
/**
* Used internally to indicate whether the mouse is within the label's window.
*/
void WinStatsLabel::
set_mouse_within(bool mouse_within) {
if (_mouse_within != mouse_within) {
_mouse_within = mouse_within;
InvalidateRect(_window, nullptr, TRUE);
}
}
/**
* Creates the window for this label.
*/
void WinStatsLabel::
create_window(HWND parent_window) {
if (_window) {
return;
}
HINSTANCE application = GetModuleHandle(nullptr);
register_window_class(application);
_window =
CreateWindow(_window_class_name, _text.c_str(), WS_CHILD | WS_CLIPSIBLINGS,
0, 0, 0, 0,
parent_window, nullptr, application, 0);
if (!_window) {
nout << "Could not create Label window!\n";
exit(1);
}
SetWindowLongPtr(_window, 0, (LONG_PTR)this);
// Create the tooltip window. This will cause a TTN_GETDISPINFO message to
// be sent to the window to acquire the tooltip text.
_tooltip_window = CreateWindow(TOOLTIPS_CLASS, nullptr,
WS_POPUP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
_window, nullptr,
application, nullptr);
if (_tooltip_window != 0) {
TOOLINFO info = { 0 };
info.cbSize = sizeof(info);
info.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
info.hwnd = _window;
info.uId = (UINT_PTR)_window;
info.lpszText = LPSTR_TEXTCALLBACK;
SendMessage(_tooltip_window, TTM_ADDTOOL, 0, (LPARAM)&info);
}
}
/**
* Registers the window class for the label window, if it has not already been
* registered.
*/
void WinStatsLabel::
register_window_class(HINSTANCE application) {
if (_window_class_registered) {
return;
}
WNDCLASS wc;
ZeroMemory(&wc, sizeof(WNDCLASS));
wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)static_window_proc;
wc.hInstance = application;
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hbrBackground = nullptr;
wc.lpszMenuName = nullptr;
wc.lpszClassName = _window_class_name;
// Reserve space to associate the this pointer with the window.
wc.cbWndExtra = sizeof(WinStatsLabel *);
if (!RegisterClass(&wc)) {
nout << "Could not register Label window class!\n";
exit(1);
}
_window_class_registered = true;
}
/**
*
*/
LONG WINAPI WinStatsLabel::
static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
WinStatsLabel *self = (WinStatsLabel *)GetWindowLongPtr(hwnd, 0);
if (self != nullptr && self->_window == hwnd) {
return self->window_proc(hwnd, msg, wparam, lparam);
} else {
return DefWindowProc(hwnd, msg, wparam, lparam);
}
}
/**
*
*/
LONG WinStatsLabel::
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
switch (msg) {
case WM_LBUTTONDBLCLK:
_graph->on_click_label(_collector_index);
return 0;
case WM_CONTEXTMENU:
_graph->on_popup_label(_collector_index);
return 0;
case WM_MOUSEMOVE:
{
// When the mouse enters the label area, highlight the label.
if (!_mouse_within) {
set_mouse_within(true);
_graph->on_enter_label(_collector_index);
}
// Now we want to get a WM_MOUSELEAVE when the mouse leaves the label.
TRACKMOUSEEVENT tme = {
sizeof(TRACKMOUSEEVENT),
TME_LEAVE,
_window,
0
};
TrackMouseEvent(&tme);
}
break;
case WM_MOUSELEAVE:
if (_mouse_within) {
set_mouse_within(false);
_graph->on_leave_label(_collector_index);
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rect = { 0, 0, _width, _height };
FillRect(hdc, &rect, (_highlight || _mouse_within) ? _highlight_bg_brush : _bg_brush);
HFONT hfnt = _monitor->get_font();
SelectObject(hdc, hfnt);
SetTextAlign(hdc, TA_LEFT | TA_TOP | TA_NOUPDATECP);
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, (_highlight || _mouse_within) ? _highlight_fg_color : _fg_color);
if (_width > 8) {
UINT format = DT_END_ELLIPSIS | DT_SINGLELINE;
if (_align_right) {
format |= DT_RIGHT;
} else {
format |= DT_LEFT;
}
RECT margins = { _left_margin, _top_margin, _width - _right_margin, _height - _bottom_margin };
DrawText(hdc, _text.data(), _text.length(), &margins, format);
}
EndPaint(hwnd, &ps);
return 0;
}
case WM_NOTIFY:
switch (((LPNMHDR)lparam)->code) {
case TTN_GETDISPINFO:
{
NMTTDISPINFO &info = *(NMTTDISPINFO *)lparam;
_tooltip_text = _graph->get_label_tooltip(_collector_index);
info.lpszText = (char *)_tooltip_text.c_str();
}
return 0;
}
break;
default:
break;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}