1001 lines
22 KiB
C++
1001 lines
22 KiB
C++
|
#include "main.h"
|
||
|
#include "./statusBar.h"
|
||
|
#include <vector>
|
||
|
|
||
|
#include <strsafe.h>
|
||
|
|
||
|
typedef struct StatusTextBlock
|
||
|
{
|
||
|
wchar_t *text;
|
||
|
size_t length;
|
||
|
long width;
|
||
|
} StatusTextBlock;
|
||
|
|
||
|
typedef struct StaturRecord
|
||
|
{
|
||
|
unsigned int id;
|
||
|
StatusTextBlock mainBlock;
|
||
|
StatusTextBlock rightBlock;
|
||
|
} StatusRecord;
|
||
|
typedef std::vector<StatusRecord*> StatusRecordList;
|
||
|
|
||
|
typedef struct StatusBar
|
||
|
{
|
||
|
HFONT font;
|
||
|
HBRUSH backBrush;
|
||
|
COLORREF textColor;
|
||
|
COLORREF backColor;
|
||
|
StatusRecordList list;
|
||
|
int idealHeight;
|
||
|
long spacing;
|
||
|
long leftBlockMinWidth;
|
||
|
BackBuffer backBuffer;
|
||
|
} StatusBar;
|
||
|
|
||
|
#define STATUSBAR(_hwnd) ((StatusBar*)(LONGX86)GetWindowLongPtrW((_hwnd), 0))
|
||
|
#define STATUSBAR_RET_VOID(_self, _hwnd) {(_self) = STATUSBAR((_hwnd)); if (NULL == (_self)) return;}
|
||
|
#define STATUSBAR_RET_VAL(_self, _hwnd, _error) {(_self) = STATUSBAR((_hwnd)); if (NULL == (_self)) return (_error);}
|
||
|
|
||
|
static LRESULT CALLBACK
|
||
|
StatusBar_WindowProc(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
|
||
|
|
||
|
static ATOM
|
||
|
StatusBar_GetClassAtom(HINSTANCE instance)
|
||
|
{
|
||
|
WNDCLASSEXW klass;
|
||
|
ATOM klassAtom;
|
||
|
|
||
|
klassAtom = (ATOM)GetClassInfoExW(instance, STATUSBAR_WINDOW_CLASS, &klass);
|
||
|
if (0 != klassAtom)
|
||
|
return klassAtom;
|
||
|
|
||
|
memset(&klass, 0, sizeof(klass));
|
||
|
klass.cbSize = sizeof(klass);
|
||
|
klass.style = 0;
|
||
|
klass.lpfnWndProc = StatusBar_WindowProc;
|
||
|
klass.cbClsExtra = 0;
|
||
|
klass.cbWndExtra = sizeof(StatusBar*);
|
||
|
klass.hInstance = instance;
|
||
|
klass.hIcon = NULL;
|
||
|
klass.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
|
||
|
klass.hbrBackground = NULL;
|
||
|
klass.lpszMenuName = NULL;
|
||
|
klass.lpszClassName = STATUSBAR_WINDOW_CLASS;
|
||
|
klass.hIconSm = NULL;
|
||
|
klassAtom = RegisterClassExW(&klass);
|
||
|
|
||
|
return klassAtom;
|
||
|
}
|
||
|
|
||
|
HWND
|
||
|
StatusBar_CreateWindow(unsigned long windowExStyle, const wchar_t *text, unsigned long windowStyle,
|
||
|
int x, int y, int width, int height,
|
||
|
HWND parentWindow, unsigned int controlId)
|
||
|
{
|
||
|
HINSTANCE instance = GetModuleHandleW(NULL);
|
||
|
ATOM klassAtom = StatusBar_GetClassAtom(instance);
|
||
|
if (0 == klassAtom)
|
||
|
return NULL;
|
||
|
|
||
|
return CreateWindowExW(WS_EX_NOPARENTNOTIFY | windowExStyle, (LPCWSTR)MAKEINTATOM(klassAtom), text,
|
||
|
WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | windowStyle,
|
||
|
x, y, width, height, parentWindow, (HMENU)controlId, instance, NULL);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
StatusBar_InitTextBlock(StatusTextBlock *block)
|
||
|
{
|
||
|
if (NULL != block)
|
||
|
{
|
||
|
block->text = NULL;
|
||
|
block->length = ((size_t)-1);
|
||
|
block->width = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
StatusBar_FreeTextBlock(StatusTextBlock *block)
|
||
|
{
|
||
|
if (NULL != block)
|
||
|
{
|
||
|
ResourceString_Free(block->text);
|
||
|
StatusBar_InitTextBlock(block);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static const wchar_t *
|
||
|
StatusBar_RetriveText(StatusTextBlock *block)
|
||
|
{
|
||
|
const wchar_t *source;
|
||
|
if (NULL == block)
|
||
|
return NULL;
|
||
|
|
||
|
source = block->text;
|
||
|
if (FALSE != IS_INTRESOURCE(source) &&
|
||
|
NULL != source)
|
||
|
{
|
||
|
wchar_t buffer[256] = {0};
|
||
|
if (NULL == WASABI_API_LNG)
|
||
|
return NULL;
|
||
|
|
||
|
WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)source, buffer, ARRAYSIZE(buffer));
|
||
|
block->text = String_Duplicate(buffer);
|
||
|
}
|
||
|
return block->text;
|
||
|
}
|
||
|
|
||
|
static size_t
|
||
|
StatusBar_GetTextBlockLength(StatusTextBlock *block)
|
||
|
{
|
||
|
const wchar_t *text;
|
||
|
|
||
|
if (NULL == block)
|
||
|
return NULL;
|
||
|
|
||
|
if (((size_t)-1) != block->length)
|
||
|
{
|
||
|
text = StatusBar_RetriveText(block);
|
||
|
block->length = (NULL != text) ? lstrlenW(text) : 0;
|
||
|
}
|
||
|
|
||
|
return block->length;
|
||
|
}
|
||
|
|
||
|
static const wchar_t *
|
||
|
StatusBar_GetTextBlockInfo(StatusTextBlock *block, HDC hdc)
|
||
|
{
|
||
|
const wchar_t *text;
|
||
|
|
||
|
text = StatusBar_RetriveText(block);
|
||
|
|
||
|
if (((size_t)-1) == block->length)
|
||
|
{
|
||
|
|
||
|
if (FALSE == IS_STRING_EMPTY(text))
|
||
|
block->length = lstrlenW(text);
|
||
|
else
|
||
|
block->length = 0;
|
||
|
}
|
||
|
|
||
|
if (-1 == block->width)
|
||
|
{
|
||
|
block->width = 0;
|
||
|
|
||
|
if (0 != block->length)
|
||
|
{
|
||
|
RECT rect;
|
||
|
DRAWTEXTPARAMS textParams;
|
||
|
|
||
|
textParams.cbSize = sizeof(textParams);
|
||
|
textParams.iTabLength = 4;
|
||
|
textParams.iLeftMargin = 0;
|
||
|
textParams.iRightMargin = 0;
|
||
|
|
||
|
SetRect(&rect, 0, 0, 0x7FFFFFFF, 0);
|
||
|
|
||
|
if (FALSE != DrawTextEx(hdc, (wchar_t*)text, -1, &rect,
|
||
|
DT_LEFT | DT_TOP | DT_TABSTOP | DT_SINGLELINE |
|
||
|
DT_NOPREFIX | DT_EXPANDTABS | DT_NOCLIP | DT_CALCRECT | DT_EDITCONTROL,
|
||
|
&textParams))
|
||
|
{
|
||
|
block->width = RECTWIDTH(rect);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEXTMETRIC metrics;
|
||
|
if (FALSE != GetTextMetrics(hdc, &metrics))
|
||
|
{
|
||
|
block->width += metrics.tmAveCharWidth/2;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return text;
|
||
|
}
|
||
|
|
||
|
static unsigned int
|
||
|
StatusBar_GetNextFreeId(StatusBar *self)
|
||
|
{
|
||
|
unsigned int id;
|
||
|
size_t index, count;
|
||
|
StatusRecord *record;
|
||
|
BOOL checkId;
|
||
|
|
||
|
count = self->list.size();
|
||
|
id = (unsigned int)count;
|
||
|
do
|
||
|
{
|
||
|
if (0xFFFFFFFF == id)
|
||
|
return STATUS_ERROR;
|
||
|
|
||
|
checkId = FALSE;
|
||
|
index = count;
|
||
|
while(index--)
|
||
|
{
|
||
|
record = self->list[index];
|
||
|
if (record->id == id)
|
||
|
{
|
||
|
id++;
|
||
|
checkId = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} while(FALSE != checkId);
|
||
|
|
||
|
return id;
|
||
|
}
|
||
|
|
||
|
static StatusRecord *
|
||
|
StatusBar_AddRecord(StatusBar *self, const wchar_t *text)
|
||
|
{
|
||
|
StatusRecord *record;
|
||
|
unsigned int id;
|
||
|
|
||
|
id = StatusBar_GetNextFreeId(self);
|
||
|
if (STATUS_ERROR == id)
|
||
|
return NULL;
|
||
|
|
||
|
record = (StatusRecord*)malloc(sizeof(StatusRecord));
|
||
|
if(NULL == record)
|
||
|
return NULL;
|
||
|
|
||
|
record->id = 0;
|
||
|
StatusBar_InitTextBlock(&record->mainBlock);
|
||
|
StatusBar_InitTextBlock(&record->rightBlock);
|
||
|
|
||
|
record->mainBlock.text = ResourceString_Duplicate(text);
|
||
|
|
||
|
self->list.push_back(record);
|
||
|
|
||
|
return record;
|
||
|
}
|
||
|
|
||
|
static StatusRecord *
|
||
|
StatusBar_FindRecord(StatusBar *self, unsigned int id, size_t *indexOut)
|
||
|
{
|
||
|
StatusRecord *record;
|
||
|
size_t index;
|
||
|
|
||
|
index = self->list.size();
|
||
|
while(index--)
|
||
|
{
|
||
|
record = self->list[index];
|
||
|
if (record->id == id)
|
||
|
{
|
||
|
if (NULL != indexOut)
|
||
|
*indexOut = index;
|
||
|
return record;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static StatusRecord *
|
||
|
StatusBar_FindVisibleRecord(StatusBar *self, size_t *indexOut)
|
||
|
{
|
||
|
StatusRecord *record;
|
||
|
size_t index;
|
||
|
const wchar_t *text;
|
||
|
|
||
|
index = self->list.size();
|
||
|
while(index--)
|
||
|
{
|
||
|
record = self->list[index];
|
||
|
|
||
|
text = StatusBar_RetriveText(&record->mainBlock);
|
||
|
if (FALSE != IS_STRING_EMPTY(text))
|
||
|
text = StatusBar_RetriveText(&record->rightBlock);
|
||
|
|
||
|
if (FALSE == IS_STRING_EMPTY(text))
|
||
|
{
|
||
|
if (NULL != indexOut)
|
||
|
*indexOut = index;
|
||
|
return record;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
StatusBar_Paint(HWND hwnd, HDC hdc, const RECT *paintRect, BOOL erase)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
StatusRecord *record;
|
||
|
const wchar_t *text;
|
||
|
|
||
|
STATUSBAR_RET_VOID(self, hwnd);
|
||
|
|
||
|
if (FALSE != erase)
|
||
|
{
|
||
|
FillRect(hdc, paintRect, self->backBrush);
|
||
|
}
|
||
|
|
||
|
record = StatusBar_FindVisibleRecord(self, NULL);
|
||
|
if (NULL != record)
|
||
|
{
|
||
|
COLORREF prevBackColor, prevTextColor;
|
||
|
HFONT prevFont;
|
||
|
RECT clientRect, textRect;
|
||
|
DRAWTEXTPARAMS textParams;
|
||
|
long limit;
|
||
|
|
||
|
prevBackColor = SetBkColor(hdc, self->backColor);
|
||
|
prevTextColor = SetTextColor(hdc, self->textColor);
|
||
|
prevFont = SelectFont(hdc, self->font);
|
||
|
|
||
|
textParams.cbSize = sizeof(textParams);
|
||
|
textParams.iTabLength = 4;
|
||
|
textParams.iLeftMargin = 0;
|
||
|
textParams.iRightMargin = 0;
|
||
|
|
||
|
GetClientRect(hwnd, &clientRect);
|
||
|
|
||
|
if (-1 == self->spacing)
|
||
|
self->spacing = Graphics_GetAveStrWidth(hdc, 2);
|
||
|
if (-1 == self->leftBlockMinWidth)
|
||
|
self->leftBlockMinWidth = Graphics_GetAveStrWidth(hdc, 16);
|
||
|
|
||
|
text = StatusBar_GetTextBlockInfo(&record->rightBlock, hdc);
|
||
|
if (FALSE == IS_STRING_EMPTY(text))
|
||
|
{
|
||
|
CopyRect(&textRect, &clientRect);
|
||
|
textRect.left = textRect.right - record->rightBlock.width;
|
||
|
limit = clientRect.left + self->spacing + self->leftBlockMinWidth;
|
||
|
if (textRect.left < limit)
|
||
|
textRect.left = limit;
|
||
|
|
||
|
|
||
|
if (textRect.left < textRect.right)
|
||
|
{
|
||
|
DrawTextEx(hdc, (wchar_t*)text, -1, &textRect,
|
||
|
DT_LEFT | DT_BOTTOM | DT_TABSTOP | DT_SINGLELINE |
|
||
|
DT_NOPREFIX | DT_EXPANDTABS, &textParams);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
text = StatusBar_GetTextBlockInfo(&record->mainBlock, hdc);
|
||
|
if (FALSE == IS_STRING_EMPTY(text))
|
||
|
{
|
||
|
CopyRect(&textRect, &clientRect);
|
||
|
textRect.right = textRect.left + record->mainBlock.width;
|
||
|
limit = clientRect.right - record->rightBlock.width - 8;
|
||
|
if (limit < self->leftBlockMinWidth)
|
||
|
limit = self->leftBlockMinWidth;
|
||
|
if (textRect.right > limit)
|
||
|
textRect.right = limit;
|
||
|
|
||
|
|
||
|
if (textRect.left < textRect.right)
|
||
|
{
|
||
|
DrawTextEx(hdc, (wchar_t*)text, -1, &textRect,
|
||
|
DT_LEFT | DT_BOTTOM | DT_TABSTOP | DT_SINGLELINE |
|
||
|
DT_NOPREFIX | DT_EXPANDTABS | DT_END_ELLIPSIS, &textParams);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
SetBkColor(hdc, prevBackColor);
|
||
|
SetTextColor(hdc, prevTextColor);
|
||
|
SelectFont(hdc, prevFont);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
StatusBar_PaintBuffered(HWND hwnd, HDC hdc, const RECT *paintRect, BOOL erase)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
HDC bufferDC, targetDC;
|
||
|
RECT clientRect;
|
||
|
|
||
|
STATUSBAR_RET_VOID(self, hwnd);
|
||
|
|
||
|
GetClientRect(hwnd, &clientRect);
|
||
|
|
||
|
if (FALSE != BackBuffer_EnsureSizeEx(&self->backBuffer,
|
||
|
RECTWIDTH(*paintRect), RECTHEIGHT(*paintRect),
|
||
|
RECTWIDTH(clientRect), RECTHEIGHT(clientRect)))
|
||
|
{
|
||
|
|
||
|
bufferDC = BackBuffer_GetDC(&self->backBuffer);
|
||
|
if (NULL != bufferDC)
|
||
|
{
|
||
|
SetViewportOrgEx(bufferDC, -paintRect->left, -paintRect->top, NULL);
|
||
|
targetDC = hdc;
|
||
|
hdc = bufferDC;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bufferDC = NULL;
|
||
|
targetDC = NULL;
|
||
|
}
|
||
|
|
||
|
StatusBar_Paint(hwnd, hdc, paintRect, erase);
|
||
|
|
||
|
if (NULL != bufferDC)
|
||
|
{
|
||
|
hdc = targetDC;
|
||
|
|
||
|
SetViewportOrgEx(bufferDC, 0, 0, NULL);
|
||
|
|
||
|
BackBuffer_Copy(&self->backBuffer, hdc,
|
||
|
paintRect->left, paintRect->top, RECTWIDTH(*paintRect), RECTHEIGHT(*paintRect));
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static BOOL
|
||
|
StatusBar_InvalidateByIndex(StatusBar *self, HWND hwnd, size_t recordIndex)
|
||
|
{
|
||
|
unsigned int windowStyle;
|
||
|
size_t visibleIndex;
|
||
|
|
||
|
windowStyle = GetWindowStyle(hwnd);
|
||
|
if (0 == (WS_VISIBLE & windowStyle))
|
||
|
return FALSE;
|
||
|
|
||
|
if(NULL != StatusBar_FindVisibleRecord(self, &visibleIndex))
|
||
|
{
|
||
|
if (recordIndex == visibleIndex)
|
||
|
return InvalidateRect(hwnd, NULL, FALSE);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
|
||
|
}
|
||
|
|
||
|
static BOOL
|
||
|
StatusBar_InvalidateByRecord(StatusBar *self, HWND hwnd, StatusRecord *record)
|
||
|
{
|
||
|
unsigned int windowStyle;
|
||
|
StatusRecord *visibleRecord;
|
||
|
|
||
|
windowStyle = GetWindowStyle(hwnd);
|
||
|
if (0 == (WS_VISIBLE & windowStyle))
|
||
|
return FALSE;
|
||
|
|
||
|
visibleRecord = StatusBar_FindVisibleRecord(self, NULL);
|
||
|
if (record == visibleRecord &&
|
||
|
NULL != visibleRecord)
|
||
|
{
|
||
|
return InvalidateRect(hwnd, NULL, FALSE);
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
static LRESULT
|
||
|
StatusBar_OnCreate(HWND hwnd, CREATESTRUCT *createStruct)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
|
||
|
self = new StatusBar();
|
||
|
if (NULL == self)
|
||
|
return -1;
|
||
|
|
||
|
SetLastError(ERROR_SUCCESS);
|
||
|
if (!SetWindowLongPtr(hwnd, 0, (LONGX86)self) && ERROR_SUCCESS != GetLastError())
|
||
|
{
|
||
|
delete self;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (NULL != createStruct->lpszName)
|
||
|
StatusBar_AddRecord(self, createStruct->lpszName);
|
||
|
|
||
|
self->backBrush = GetSysColorBrush(COLOR_WINDOW);
|
||
|
self->backColor = GetSysColor(COLOR_WINDOW);
|
||
|
self->textColor = GetSysColor(COLOR_WINDOWTEXT);
|
||
|
self->idealHeight = -1;
|
||
|
self->spacing = -1;
|
||
|
self->leftBlockMinWidth = -1;
|
||
|
|
||
|
|
||
|
BackBuffer_Initialize(&self->backBuffer, hwnd);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
StatusBar_OnDestroy(HWND hwnd)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
size_t index;
|
||
|
StatusRecord *record;
|
||
|
|
||
|
self = STATUSBAR(hwnd);
|
||
|
SetWindowLongPtr(hwnd, 0, 0);
|
||
|
|
||
|
if (NULL == self)
|
||
|
return;
|
||
|
|
||
|
index = self->list.size();
|
||
|
while(index--)
|
||
|
{
|
||
|
record = self->list[index];
|
||
|
StatusBar_FreeTextBlock(&record->mainBlock);
|
||
|
StatusBar_FreeTextBlock(&record->rightBlock);
|
||
|
}
|
||
|
|
||
|
BackBuffer_Uninitialize(&self->backBuffer);
|
||
|
|
||
|
delete self;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
StatusBar_OnPaint(HWND hwnd)
|
||
|
{
|
||
|
PAINTSTRUCT ps;
|
||
|
|
||
|
if (NULL != BeginPaint(hwnd, &ps))
|
||
|
{
|
||
|
StatusBar_PaintBuffered(hwnd, ps.hdc, &ps.rcPaint, ps.fErase);
|
||
|
EndPaint(hwnd, &ps);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
StatusBar_OnPrintClient(HWND hwnd, HDC hdc, UINT options)
|
||
|
{
|
||
|
RECT clientRect;
|
||
|
if (GetClientRect(hwnd, &clientRect))
|
||
|
{
|
||
|
StatusBar_Paint(hwnd, hdc, &clientRect, TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
StatusBar_OnWindowPosChanged(HWND hwnd, WINDOWPOS *windowPos)
|
||
|
{
|
||
|
if (SWP_NOSIZE != ((SWP_NOSIZE | SWP_FRAMECHANGED) & windowPos->flags) &&
|
||
|
0 == (SWP_NOREDRAW & windowPos->flags))
|
||
|
{
|
||
|
InvalidateRect(hwnd, NULL, FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static LRESULT
|
||
|
StatusBar_OnSetText(HWND hwnd, LPCWSTR text)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
StatusRecord *record;
|
||
|
size_t count;
|
||
|
|
||
|
STATUSBAR_RET_VAL(self, hwnd, FALSE);
|
||
|
|
||
|
count = self->list.size();
|
||
|
if (0 == count)
|
||
|
{
|
||
|
if (NULL == text)
|
||
|
return TRUE;
|
||
|
|
||
|
record = StatusBar_AddRecord(self, text);
|
||
|
if (NULL == record)
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
record = self->list[count - 1];
|
||
|
StatusBar_FreeTextBlock(&record->mainBlock);
|
||
|
StatusBar_FreeTextBlock(&record->rightBlock);
|
||
|
|
||
|
record->mainBlock.text = ResourceString_Duplicate(text);
|
||
|
}
|
||
|
|
||
|
StatusBar_InvalidateByRecord(self, hwnd, record);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static LRESULT
|
||
|
StatusBar_OnGetText(HWND hwnd, LPWSTR buffer, size_t bufferMax)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
StatusRecord *record;
|
||
|
const wchar_t *lText, *rText;
|
||
|
size_t count, remaining;
|
||
|
wchar_t *cursor;
|
||
|
HRESULT hr;
|
||
|
|
||
|
STATUSBAR_RET_VAL(self, hwnd, 0);
|
||
|
|
||
|
if (NULL == buffer)
|
||
|
return 0;
|
||
|
|
||
|
count = self->list.size();
|
||
|
if (0 == count)
|
||
|
{
|
||
|
lText = NULL;
|
||
|
rText = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
record = self->list[count - 1];
|
||
|
lText = StatusBar_RetriveText(&record->mainBlock);
|
||
|
rText = StatusBar_RetriveText(&record->rightBlock);
|
||
|
}
|
||
|
|
||
|
cursor = buffer;
|
||
|
remaining = bufferMax;
|
||
|
|
||
|
if (NULL != lText)
|
||
|
hr = StringCchCopyEx(cursor, bufferMax, lText, &cursor, &remaining, 0);
|
||
|
else
|
||
|
hr = S_OK;
|
||
|
|
||
|
if (NULL != rText && SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = StringCchCopyEx(cursor, bufferMax, L"\f", &cursor, &remaining, 0);
|
||
|
if (SUCCEEDED(hr))
|
||
|
hr = StringCchCopyEx(cursor, bufferMax, rText, &cursor, &remaining, 0);
|
||
|
}
|
||
|
|
||
|
return (bufferMax - remaining);
|
||
|
}
|
||
|
|
||
|
static LRESULT
|
||
|
StatusBar_OnGetTextLength(HWND hwnd)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
StatusRecord *record;
|
||
|
size_t length, r;
|
||
|
|
||
|
STATUSBAR_RET_VAL(self, hwnd, 0);
|
||
|
|
||
|
length = self->list.size();
|
||
|
if (0 == length)
|
||
|
return 0;
|
||
|
|
||
|
record = self->list[length - 1];
|
||
|
length = StatusBar_GetTextBlockLength(&record->mainBlock);
|
||
|
r = StatusBar_GetTextBlockLength(&record->rightBlock);
|
||
|
if (0 != r)
|
||
|
{
|
||
|
length += (r + 1);
|
||
|
}
|
||
|
|
||
|
return length;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
StatusBar_OnSetFont(HWND hwnd, HFONT font, BOOL redraw)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
StatusRecord *record;
|
||
|
size_t index;
|
||
|
|
||
|
STATUSBAR_RET_VOID(self, hwnd);
|
||
|
|
||
|
self->font = font;
|
||
|
self->idealHeight = -1;
|
||
|
self->spacing = -1;
|
||
|
self->leftBlockMinWidth = -1;
|
||
|
|
||
|
index = self->list.size();
|
||
|
while(index--)
|
||
|
{
|
||
|
record = self->list[index];
|
||
|
record->mainBlock.width = -1;
|
||
|
record->rightBlock.width = -1;
|
||
|
}
|
||
|
|
||
|
if (NULL != redraw)
|
||
|
InvalidateRect(hwnd, NULL, TRUE);
|
||
|
}
|
||
|
|
||
|
static LRESULT
|
||
|
StatusBar_OnGetFont(HWND hwnd)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
STATUSBAR_RET_VAL(self, hwnd, NULL);
|
||
|
|
||
|
return (LRESULT)self->font;
|
||
|
}
|
||
|
|
||
|
static LRESULT
|
||
|
StatusBar_OnSetBackBrush(HWND hwnd, HBRUSH brush, BOOL redraw)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
HBRUSH prevBrush;
|
||
|
|
||
|
STATUSBAR_RET_VAL(self, hwnd, (LRESULT)GetSysColorBrush(COLOR_WINDOW));
|
||
|
|
||
|
prevBrush = self->backBrush;
|
||
|
self->backBrush = brush;
|
||
|
|
||
|
if (NULL != redraw)
|
||
|
InvalidateRect(hwnd, NULL, TRUE);
|
||
|
|
||
|
return (LRESULT)prevBrush;
|
||
|
}
|
||
|
|
||
|
static LRESULT
|
||
|
StatusBar_OnGetBackBrush(HWND hwnd)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
|
||
|
STATUSBAR_RET_VAL(self, hwnd, (LRESULT)GetSysColorBrush(COLOR_WINDOW));
|
||
|
|
||
|
return (LRESULT)self->backBrush;
|
||
|
}
|
||
|
|
||
|
static LRESULT
|
||
|
StatusBar_OnSetBackColor(HWND hwnd, COLORREF color, BOOL redraw)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
COLORREF prevColor;
|
||
|
|
||
|
STATUSBAR_RET_VAL(self, hwnd, GetSysColor(COLOR_WINDOW));
|
||
|
|
||
|
prevColor = self->backColor;
|
||
|
self->backColor = color;
|
||
|
|
||
|
if (NULL != redraw)
|
||
|
InvalidateRect(hwnd, NULL, FALSE);
|
||
|
|
||
|
return (LRESULT)prevColor;
|
||
|
}
|
||
|
|
||
|
static LRESULT
|
||
|
StatusBar_OnGetBackColor(HWND hwnd)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
STATUSBAR_RET_VAL(self, hwnd, GetSysColor(COLOR_WINDOW));
|
||
|
|
||
|
return (LRESULT)self->backColor;
|
||
|
|
||
|
}
|
||
|
|
||
|
static LRESULT
|
||
|
StatusBar_OnSetTextColor(HWND hwnd, COLORREF color, BOOL redraw)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
COLORREF prevColor;
|
||
|
|
||
|
STATUSBAR_RET_VAL(self, hwnd, GetSysColor(COLOR_WINDOWTEXT));
|
||
|
|
||
|
prevColor = self->textColor;
|
||
|
self->textColor = color;
|
||
|
|
||
|
if (NULL != redraw)
|
||
|
InvalidateRect(hwnd, NULL, FALSE);
|
||
|
|
||
|
return (LRESULT)prevColor;
|
||
|
}
|
||
|
|
||
|
static LRESULT
|
||
|
StatusBar_OnGetTextColor(HWND hwnd)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
STATUSBAR_RET_VAL(self, hwnd, GetSysColor(COLOR_WINDOWTEXT));
|
||
|
|
||
|
return (LRESULT)self->textColor;
|
||
|
}
|
||
|
|
||
|
static LRESULT
|
||
|
StatusBar_OnGetIdealHeight(HWND hwnd)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
STATUSBAR_RET_VAL(self, hwnd, 0);
|
||
|
|
||
|
if (self->idealHeight < 0)
|
||
|
{
|
||
|
HDC hdc;
|
||
|
|
||
|
self->idealHeight = 0;
|
||
|
|
||
|
hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
|
||
|
if (NULL != hdc)
|
||
|
{
|
||
|
TEXTMETRIC metrics;
|
||
|
HFONT font, prevFont;
|
||
|
|
||
|
font = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L);
|
||
|
prevFont = SelectFont(hdc, font);
|
||
|
|
||
|
if (FALSE != GetTextMetrics(hdc, &metrics))
|
||
|
self->idealHeight = metrics.tmHeight;
|
||
|
|
||
|
SelectFont(hdc, prevFont);
|
||
|
ReleaseDC(hwnd, hdc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (LRESULT)self->idealHeight;
|
||
|
|
||
|
}
|
||
|
static LRESULT
|
||
|
StatusBar_OnAddStatus(HWND hwnd, const wchar_t *text)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
StatusRecord *record;
|
||
|
|
||
|
STATUSBAR_RET_VAL(self, hwnd, STATUS_ERROR);
|
||
|
|
||
|
record = StatusBar_AddRecord(self, text);
|
||
|
if (NULL == record)
|
||
|
return STATUS_ERROR;
|
||
|
|
||
|
StatusBar_InvalidateByRecord(self, hwnd, record);
|
||
|
|
||
|
return record->id;
|
||
|
}
|
||
|
|
||
|
static LRESULT
|
||
|
StatusBar_OnRemoveStatus(HWND hwnd, unsigned int statusId)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
StatusRecord *record;
|
||
|
size_t index;
|
||
|
STATUSBAR_RET_VAL(self, hwnd, FALSE);
|
||
|
|
||
|
record = StatusBar_FindRecord(self, statusId, &index);
|
||
|
if (NULL == record)
|
||
|
return FALSE;
|
||
|
|
||
|
StatusBar_InvalidateByRecord(self, hwnd, record);
|
||
|
|
||
|
self->list.erase(self->list.begin() + index);
|
||
|
|
||
|
StatusBar_FreeTextBlock(&record->mainBlock);
|
||
|
StatusBar_FreeTextBlock(&record->rightBlock);
|
||
|
|
||
|
free(record);
|
||
|
|
||
|
return (LRESULT)TRUE;
|
||
|
}
|
||
|
|
||
|
static LRESULT
|
||
|
StatusBar_OnSetStatusText(HWND hwnd, unsigned int statusId, const wchar_t *text)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
StatusRecord *record;
|
||
|
size_t index;
|
||
|
|
||
|
STATUSBAR_RET_VAL(self, hwnd, FALSE);
|
||
|
|
||
|
record = StatusBar_FindRecord(self, statusId, &index);
|
||
|
if (NULL == record)
|
||
|
return FALSE;
|
||
|
|
||
|
StatusBar_InvalidateByRecord(self, hwnd, record);
|
||
|
|
||
|
StatusBar_FreeTextBlock(&record->mainBlock);
|
||
|
record->mainBlock.text = ResourceString_Duplicate(text);
|
||
|
|
||
|
StatusBar_InvalidateByRecord(self, hwnd, record);
|
||
|
|
||
|
return (LRESULT)TRUE;
|
||
|
}
|
||
|
|
||
|
static LRESULT
|
||
|
StatusBar_OnSetStatusRightText(HWND hwnd, unsigned int statusId, const wchar_t *text)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
StatusRecord *record;
|
||
|
size_t index;
|
||
|
|
||
|
STATUSBAR_RET_VAL(self, hwnd, FALSE);
|
||
|
|
||
|
record = StatusBar_FindRecord(self, statusId, &index);
|
||
|
if (NULL == record)
|
||
|
return FALSE;
|
||
|
|
||
|
StatusBar_InvalidateByRecord(self, hwnd, record);
|
||
|
|
||
|
StatusBar_FreeTextBlock(&record->rightBlock);
|
||
|
record->rightBlock.text = ResourceString_Duplicate(text);
|
||
|
|
||
|
StatusBar_InvalidateByRecord(self, hwnd, record);
|
||
|
|
||
|
return (LRESULT)TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
static LRESULT
|
||
|
StatusBar_OnMoveStatus(HWND hwnd, unsigned int statusId, unsigned int moveCommand)
|
||
|
{
|
||
|
StatusBar *self;
|
||
|
StatusRecord *record;
|
||
|
size_t index, count, newIndex;
|
||
|
|
||
|
STATUSBAR_RET_VAL(self, hwnd, FALSE);
|
||
|
|
||
|
record = StatusBar_FindRecord(self, statusId, &index);
|
||
|
if (NULL == record)
|
||
|
return FALSE;
|
||
|
|
||
|
count = self->list.size();
|
||
|
|
||
|
switch(moveCommand)
|
||
|
{
|
||
|
|
||
|
case STATUS_MOVE_BOTTOM:
|
||
|
if (0 == index)
|
||
|
return TRUE;
|
||
|
self->list.erase(self->list.begin() + index);
|
||
|
self->list.insert(self->list.begin(), record);
|
||
|
newIndex = 0;
|
||
|
break;
|
||
|
|
||
|
case STATUS_MOVE_TOP:
|
||
|
if (index == (count - 1))
|
||
|
return TRUE;
|
||
|
|
||
|
self->list.erase(self->list.begin() + index);
|
||
|
self->list.push_back(record);
|
||
|
newIndex = count - 1;
|
||
|
break;
|
||
|
|
||
|
case STATUS_MOVE_UP:
|
||
|
if (index == (count - 1))
|
||
|
return TRUE;
|
||
|
|
||
|
self->list.erase(self->list.begin() + index);
|
||
|
newIndex = index + 1;
|
||
|
self->list.insert(self->list.begin() + newIndex, record);
|
||
|
break;
|
||
|
|
||
|
case STATUS_MOVE_DOWN:
|
||
|
if (index == 0)
|
||
|
return TRUE;
|
||
|
|
||
|
self->list.erase(self->list.begin() + index);
|
||
|
newIndex = index - 1;
|
||
|
self->list.insert(self->list.begin() + newIndex, record);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (index != newIndex)
|
||
|
{
|
||
|
StatusBar_InvalidateByIndex(self, hwnd, index);
|
||
|
StatusBar_InvalidateByIndex(self, hwnd, newIndex);
|
||
|
}
|
||
|
|
||
|
return (LRESULT)TRUE;
|
||
|
}
|
||
|
|
||
|
static LRESULT CALLBACK
|
||
|
StatusBar_WindowProc(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
switch(uMsg)
|
||
|
{
|
||
|
case WM_CREATE: return StatusBar_OnCreate(hwnd, (CREATESTRUCT*)lParam);
|
||
|
case WM_DESTROY: StatusBar_OnDestroy(hwnd); return 0;
|
||
|
case WM_PAINT: StatusBar_OnPaint(hwnd); return 0;
|
||
|
case WM_PRINTCLIENT: StatusBar_OnPrintClient(hwnd, (HDC)wParam, (UINT)lParam); return 0;
|
||
|
case WM_PRINT: return 0;
|
||
|
case WM_ERASEBKGND: return 0;
|
||
|
case WM_WINDOWPOSCHANGED: StatusBar_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return 0;
|
||
|
case WM_SIZE: return 0;
|
||
|
case WM_MOVE: return 0;
|
||
|
case WM_SETTEXT: return StatusBar_OnSetText(hwnd, (LPCWSTR)lParam);
|
||
|
case WM_GETTEXT: return StatusBar_OnGetText(hwnd, (LPWSTR)lParam, (INT)wParam);
|
||
|
case WM_GETTEXTLENGTH: return StatusBar_OnGetTextLength(hwnd);
|
||
|
case WM_SETFONT: StatusBar_OnSetFont(hwnd, (HFONT)wParam, (BOOL)LOWORD(lParam)); return 0;
|
||
|
case WM_GETFONT: return StatusBar_OnGetFont(hwnd);
|
||
|
|
||
|
case STATUSBAR_WM_SET_BACK_BRUSH: return StatusBar_OnSetBackBrush(hwnd, (HBRUSH)lParam, (BOOL)wParam);
|
||
|
case STATUSBAR_WM_GET_BACK_BRUSH: return StatusBar_OnGetBackBrush(hwnd);
|
||
|
case STATUSBAR_WM_SET_BACK_COLOR: return StatusBar_OnSetBackColor(hwnd, (COLORREF)lParam, (BOOL)wParam);
|
||
|
case STATUSBAR_WM_GET_BACK_COLOR: return StatusBar_OnGetBackColor(hwnd);
|
||
|
case STATUSBAR_WM_SET_TEXT_COLOR: return StatusBar_OnSetTextColor(hwnd, (COLORREF)lParam, (BOOL)wParam);
|
||
|
case STATUSBAR_WM_GET_TEXT_COLOR: return StatusBar_OnGetTextColor(hwnd);
|
||
|
case STATUSBAR_WM_GET_IDEAL_HEIGHT: return StatusBar_OnGetIdealHeight(hwnd);
|
||
|
case STATUSBAR_WM_ADD_STATUS: return StatusBar_OnAddStatus(hwnd, (const wchar_t*)lParam);
|
||
|
case STATUSBAR_WM_REMOVE_STATUS: return StatusBar_OnRemoveStatus(hwnd, (unsigned int)(wParam));
|
||
|
case STATUSBAR_WM_SET_STATUS_TEXT: return StatusBar_OnSetStatusText(hwnd, (unsigned int)(wParam), (const wchar_t*)lParam);
|
||
|
case STATUSBAR_WM_SET_STATUS_RTEXT: return StatusBar_OnSetStatusRightText(hwnd, (unsigned int)(wParam), (const wchar_t*)lParam);
|
||
|
case STATUSBAR_WM_MOVE_STATUS: return StatusBar_OnMoveStatus(hwnd, (unsigned int)(wParam), (unsigned int)lParam);
|
||
|
}
|
||
|
|
||
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||
|
}
|