update header comment email; sync bug fixes into 'mc' version

main
Allen Webster 2024-01-19 19:36:38 -08:00
parent 08dc9c445d
commit 3638407c42
2 changed files with 1101 additions and 1099 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/* /*
** Win32 Custom Window Example Program ** Win32 Custom Window Example Program
** v1.2 - April 30th 2020 ** v1.3.1 - Jan 19th 2024
** by Allen Webster allenwebster@4coder.net ** by Allen Webster allenw@mr4th.com
** **
** public domain example program ** public domain example program
** NO WARRANTY IMPLIED; USE AT YOUR OWN RISK ** NO WARRANTY IMPLIED; USE AT YOUR OWN RISK
@ -29,23 +29,23 @@ void ToggleMaximize(HWND hwnd);
void EmbeddedWidgetRect(RECT rect); void EmbeddedWidgetRect(RECT rect);
typedef enum{ typedef enum{
InputEventKind_MouseLeftPress, InputEventKind_MouseLeftPress,
InputEventKind_MouseLeftRelease, InputEventKind_MouseLeftRelease,
} Input_Event_Kind; } Input_Event_Kind;
typedef struct Input_Event Input_Event; typedef struct Input_Event Input_Event;
struct Input_Event{ struct Input_Event{
Input_Event *next; Input_Event *next;
Input_Event_Kind kind; Input_Event_Kind kind;
}; };
typedef struct Input Input; typedef struct Input Input;
struct Input{ struct Input{
Input_Event *first_event; Input_Event *first_event;
Input_Event *last_event; Input_Event *last_event;
int mouse_x; int mouse_x;
int mouse_y; int mouse_y;
int left; int left;
}; };
void UpdateAndRender(HWND hwnd, Input *input); void UpdateAndRender(HWND hwnd, Input *input);
@ -54,7 +54,7 @@ void UpdateAndRender(HWND hwnd, Input *input);
int int
HitTest(int x, int y, RECT rect){ HitTest(int x, int y, RECT rect){
return((rect.left <= x && x < rect.right) && (rect.top <= y && y < rect.bottom)); return((rect.left <= x && x < rect.right) && (rect.top <= y && y < rect.bottom));
} }
//////////////////////////////// ////////////////////////////////
@ -67,19 +67,19 @@ int toggle_maximize_at_end_of_update = 0;
int int
WindowIsActive(void){ WindowIsActive(void){
return(window_is_active); return(window_is_active);
} }
void void
StopRunning(void){ StopRunning(void){
keep_running = 0; keep_running = 0;
} }
void void
Minimize(HWND hwnd){ Minimize(HWND hwnd){
minimize_at_end_of_update = 1; minimize_at_end_of_update = 1;
} }
void void
ToggleMaximize(HWND hwnd){ ToggleMaximize(HWND hwnd){
toggle_maximize_at_end_of_update = 1; toggle_maximize_at_end_of_update = 1;
} }
#define MAX_EMBEDDED_WIDGETS 128 #define MAX_EMBEDDED_WIDGETS 128
@ -87,10 +87,10 @@ int embedded_widget_count = 0;
RECT embedded_widget_rect[MAX_EMBEDDED_WIDGETS]; RECT embedded_widget_rect[MAX_EMBEDDED_WIDGETS];
void void
EmbeddedWidgetRect(RECT rect){ EmbeddedWidgetRect(RECT rect){
if (embedded_widget_count < MAX_EMBEDDED_WIDGETS){ if (embedded_widget_count < MAX_EMBEDDED_WIDGETS){
embedded_widget_rect[embedded_widget_count] = rect; embedded_widget_rect[embedded_widget_count] = rect;
embedded_widget_count += 1; embedded_widget_count += 1;
} }
} }
//////////////////////////////// ////////////////////////////////
@ -102,19 +102,19 @@ Input input;
Input_Event* Input_Event*
PushEvent(void){ PushEvent(void){
Input_Event *result = 0; Input_Event *result = 0;
if (input_event_cursor < MAX_INPUT_EVENT_COUNT){ if (input_event_cursor < MAX_INPUT_EVENT_COUNT){
result = &input_event_memory[input_event_cursor]; result = &input_event_memory[input_event_cursor];
input_event_cursor += 1; input_event_cursor += 1;
if (input.first_event == 0){ if (input.first_event == 0){
input.first_event = result; input.first_event = result;
}
if (input.last_event != 0){
input.last_event->next = result;
}
input.last_event = result;
} }
return(result); if (input.last_event != 0){
input.last_event->next = result;
}
input.last_event = result;
}
return(result);
} }
LRESULT LRESULT
@ -122,157 +122,157 @@ CustomBorderWindowProc(HWND hwnd,
UINT uMsg, UINT uMsg,
WPARAM wParam, WPARAM wParam,
LPARAM lParam){ LPARAM lParam){
LRESULT result = 0; LRESULT result = 0;
switch (uMsg){ switch (uMsg){
case WM_NCCALCSIZE: case WM_NCCALCSIZE:
{ {
RECT* r = (RECT*)lParam; RECT* r = (RECT*)lParam;
if (IsZoomed(hwnd)){ if (IsZoomed(hwnd)){
int x_push_in = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER); int x_push_in = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
int y_push_in = GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER); int y_push_in = GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
r->top += x_push_in; r->top += x_push_in;
r->left += y_push_in; r->left += y_push_in;
r->right -= x_push_in; r->right -= x_push_in;
r->bottom -= y_push_in; r->bottom -= y_push_in;
}
}break;
case WM_NCACTIVATE:
{
result = 1;
window_is_active = wParam;
// A convenient function for checking if a window is minimized.
if (IsIconic(hwnd)){
result = DefWindowProcW(hwnd, uMsg, wParam, -1);
}
}break;
case WM_NCHITTEST:
{
POINT pos;
pos.x = GET_X_LPARAM(lParam);
pos.y = GET_Y_LPARAM(lParam);
RECT frame_rect;
GetWindowRect(hwnd, &frame_rect);
if (!HitTest(pos.x, pos.y, frame_rect)){
result = HTNOWHERE;
}
else{
RECT rect;
GetClientRect(hwnd, &rect);
ScreenToClient(hwnd, &pos);
// Borders
int l = 0;
int r = 0;
int b = 0;
int t = 0;
if (!IsZoomed(hwnd)){
if (rect.left <= pos.x && pos.x < rect.left + border_width){
l = 1;
}
if (rect.right - border_width <= pos.x && pos.x < rect.right){
r = 1;
}
if (rect.bottom - border_width <= pos.y && pos.y < rect.bottom){
b = 1;
}
if (rect.top <= pos.y && pos.y < rect.top + border_width){
t = 1;
}
}
if (l){
if (t){
result = HTTOPLEFT;
}
else if (b){
result = HTBOTTOMLEFT;
}
else{
result = HTLEFT;
}
}
else if (r){
if (t){
result = HTTOPRIGHT;
}
else if (b){
result = HTBOTTOMRIGHT;
}
else{
result = HTRIGHT;
}
}
else if (t){
result = HTTOP;
}
else if (b){
result = HTBOTTOM;
}
// Inside
else{
if (rect.top <= pos.y && pos.y < rect.top + caption_width){
result = HTCAPTION;
for (int i = 0; i < embedded_widget_count; i += 1){
if (HitTest(pos.x, pos.y, embedded_widget_rect[i])){
result = HTCLIENT;
break;
}
} }
}break; }
else{
case WM_NCACTIVATE: result = HTCLIENT;
{ }
result = 1; }
window_is_active = wParam; }
// A convenient function for checking if a window is minimized.
if (IsIconic(hwnd)){ }break;
result = DefWindowProcW(hwnd, uMsg, wParam, -1);
} case WM_CLOSE:
}break; {
keep_running = 0;
case WM_NCHITTEST: }break;
{
POINT pos; case WM_SIZING:
pos.x = GET_X_LPARAM(lParam); {
pos.y = GET_Y_LPARAM(lParam); InvalidateRect(hwnd, 0, 0);
}break;
RECT frame_rect;
GetWindowRect(hwnd, &frame_rect); case WM_PAINT:
if (!HitTest(pos.x, pos.y, frame_rect)){ {
result = HTNOWHERE; PAINTSTRUCT ps;
} BeginPaint(hwnd, &ps);
embedded_widget_count = 0;
else{ UpdateAndRender(hwnd, 0);
EndPaint(hwnd, &ps);
RECT rect; }break;
GetClientRect(hwnd, &rect);
ScreenToClient(hwnd, &pos); case WM_LBUTTONDOWN:
{
// Borders Input_Event *event = PushEvent();
int l = 0; if (event != 0){
int r = 0; event->kind = InputEventKind_MouseLeftPress;
int b = 0; }
int t = 0; }break;
if (!IsZoomed(hwnd)){
if (rect.left <= pos.x && pos.x < rect.left + border_width){ case WM_LBUTTONUP:
l = 1; {
} Input_Event *event = PushEvent();
if (rect.right - border_width <= pos.x && pos.x < rect.right){ if (event != 0){
r = 1; event->kind = InputEventKind_MouseLeftRelease;
} }
if (rect.bottom - border_width <= pos.y && pos.y < rect.bottom){ }break;
b = 1;
} default:
if (rect.top <= pos.y && pos.y < rect.top + border_width){ {
t = 1; result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
} }break;
} }
if (l){ return(result);
if (t){
result = HTTOPLEFT;
}
else if (b){
result = HTBOTTOMLEFT;
}
else{
result = HTLEFT;
}
}
else if (r){
if (t){
result = HTTOPRIGHT;
}
else if (b){
result = HTBOTTOMRIGHT;
}
else{
result = HTRIGHT;
}
}
else if (t){
result = HTTOP;
}
else if (b){
result = HTBOTTOM;
}
// Inside
else{
if (rect.top <= pos.y && pos.y < rect.top + caption_width){
result = HTCAPTION;
for (int i = 0; i < embedded_widget_count; i += 1){
if (HitTest(pos.x, pos.y, embedded_widget_rect[i])){
result = HTCLIENT;
break;
}
}
}
else{
result = HTCLIENT;
}
}
}
}break;
case WM_CLOSE:
{
keep_running = 0;
}break;
case WM_SIZING:
{
InvalidateRect(hwnd, 0, 0);
}break;
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
embedded_widget_count = 0;
UpdateAndRender(hwnd, 0);
EndPaint(hwnd, &ps);
}break;
case WM_LBUTTONDOWN:
{
Input_Event *event = PushEvent();
if (event != 0){
event->kind = InputEventKind_MouseLeftPress;
}
}break;
case WM_LBUTTONUP:
{
Input_Event *event = PushEvent();
if (event != 0){
event->kind = InputEventKind_MouseLeftRelease;
}
}break;
default:
{
result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
}break;
}
return(result);
} }
int int
@ -280,137 +280,139 @@ WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, LPSTR lpCmdLine,
int nShowCmd){ int nShowCmd){
#define WINDOW_CLASS L"MainWindow" #define WINDOW_CLASS L"MainWindow"
WNDCLASSW window_class = {0};
window_class.style = 0;
window_class.lpfnWndProc = CustomBorderWindowProc;
window_class.hInstance = hInstance;
window_class.hCursor = LoadCursorA(0, IDC_ARROW);
window_class.lpszClassName = WINDOW_CLASS;
ATOM atom = RegisterClassW(&window_class);
if (atom == 0){
fprintf(stderr, "RegisterClassW failed\n");
exit(1);
}
DWORD style = WS_OVERLAPPEDWINDOW;
HWND hwnd = CreateWindowW(WINDOW_CLASS,
L"Window Name",
style,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
hInstance,
0);
if (hwnd == 0){
fprintf(stderr, "CreateWindowExW failed\n");
exit(1);
}
SetWindowTheme(hwnd, L" ", L" ");
BOOL composition_enabled;
if (DwmIsCompositionEnabled(&composition_enabled) != S_OK){
fprintf(stderr, "DwmIsCompositionEnabled failed\n");
composition_enabled = 0;
}
fprintf(stdout, "Has compositor? %s\n", composition_enabled?"Yes":"No");
ShowWindow(hwnd, SW_SHOW);
keep_running = 1;
for (;keep_running;){
input.first_event = 0;
input.last_event = 0;
input_event_cursor = 0;
WNDCLASSW window_class = {0}; MSG msg;
window_class.style = 0;
window_class.lpfnWndProc = CustomBorderWindowProc;
window_class.hInstance = hInstance;
window_class.hCursor = LoadCursorA(0, IDC_ARROW);
window_class.lpszClassName = WINDOW_CLASS;
ATOM atom = RegisterClassW(&window_class); if (minimize_at_end_of_update){
if (atom == 0){ ShowWindow(hwnd, SW_MINIMIZE);
fprintf(stderr, "RegisterClassW failed\n"); }
exit(1); else if (toggle_maximize_at_end_of_update){
if (IsZoomed(hwnd)){
ShowWindow(hwnd, SW_RESTORE);
}
else{
ShowWindow(hwnd, SW_MAXIMIZE);
}
}
else{
GetMessage(&msg, 0, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
} }
DWORD style = WS_OVERLAPPEDWINDOW; for (;PeekMessageW(&msg, 0, 0, 0, PM_REMOVE);){
HWND hwnd = CreateWindowW(WINDOW_CLASS, TranslateMessage(&msg);
L"Window Name", DispatchMessage(&msg);
style,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
hInstance,
0);
if (hwnd == 0){
fprintf(stderr, "CreateWindowExW failed\n");
exit(1);
} }
SetWindowTheme(hwnd, L" ", L" "); POINT mpos;
GetCursorPos(&mpos);
ScreenToClient(hwnd, &mpos);
input.mouse_x = mpos.x;
input.mouse_y = mpos.y;
input.left = (GetKeyState(VK_LBUTTON)&(1 << 15));
minimize_at_end_of_update = 0;
toggle_maximize_at_end_of_update = 0;
embedded_widget_count = 0;
UpdateAndRender(hwnd, &input);
BOOL composition_enabled; if (composition_enabled){
if (DwmIsCompositionEnabled(&composition_enabled) != S_OK){ DwmFlush();
fprintf(stderr, "DwmIsCompositionEnabled failed\n");
composition_enabled = 0;
} }
fprintf(stdout, "Has compositor? %s\n", composition_enabled?"Yes":"No"); else{
Sleep(33);
ShowWindow(hwnd, SW_SHOW);
keep_running = 1;
for (;keep_running;){
input.first_event = 0;
input.last_event = 0;
input_event_cursor = 0;
MSG msg;
if (minimize_at_end_of_update){
ShowWindow(hwnd, SW_MINIMIZE);
}
else if (toggle_maximize_at_end_of_update){
if (IsZoomed(hwnd)){
ShowWindow(hwnd, SW_RESTORE);
}
else{
ShowWindow(hwnd, SW_MAXIMIZE);
}
}
else{
GetMessage(&msg, 0, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
for (;PeekMessageW(&msg, 0, 0, 0, PM_REMOVE);){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
POINT mpos;
GetCursorPos(&mpos);
ScreenToClient(hwnd, &mpos);
input.mouse_x = mpos.x;
input.mouse_y = mpos.y;
input.left = (GetKeyState(VK_LBUTTON)&(1 << 15));
minimize_at_end_of_update = 0;
toggle_maximize_at_end_of_update = 0;
embedded_widget_count = 0;
UpdateAndRender(hwnd, &input);
if (composition_enabled){
DwmFlush();
}
else{
Sleep(33);
}
} }
}
return(0);
return(0);
} }
//////////////////////////////// ////////////////////////////////
int int
HasEvent(Input *input, Input_Event_Kind kind){ HasEvent(Input *input, Input_Event_Kind kind){
int result = 0; int result = 0;
if (input != 0){ if (input != 0){
Input_Event **ptr_to = &input->first_event; Input_Event **ptr_to = &input->first_event;
Input_Event *last = 0; Input_Event *last = 0;
for (Input_Event *event = input->first_event, *next = 0; for (Input_Event *event = input->first_event, *next = 0;
event != 0; event != 0;
event = next){ event = next){
next = event->next; next = event->next;
if (event->kind == kind){ if (event->kind == kind){
result = 1; result = 1;
*ptr_to = next; *ptr_to = next;
break; if (event == input->last_event){
} input->last_event = last;
else{
ptr_to = &event->next;
last = event;
}
} }
input->last_event = last; break;
}
else{
ptr_to = &event->next;
last = event;
}
} }
return(result); }
return(result);
} }
typedef enum{ typedef enum{
Widget_None, Widget_None,
Widget_Close, Widget_Close,
Widget_Minimize, Widget_Minimize,
Widget_Maximize, Widget_Maximize,
Widget_Slider, Widget_Slider,
} Widget; } Widget;
Widget click_started = Widget_None; Widget click_started = Widget_None;
@ -419,166 +421,166 @@ int delta_from_mouse_x = 0;
void void
UpdateAndRender(HWND hwnd, Input *input){ UpdateAndRender(HWND hwnd, Input *input){
RECT window_rect; RECT window_rect;
GetClientRect(hwnd, &window_rect); GetClientRect(hwnd, &window_rect);
RECT inside_rect;
inside_rect.top = window_rect.top + caption_width;
if (!IsZoomed(hwnd)){
inside_rect.left = window_rect.left + border_width;
inside_rect.right = window_rect.right - border_width;
inside_rect.bottom = window_rect.bottom - border_width;
}
else{
inside_rect.left = window_rect.left;
inside_rect.right = window_rect.right;
inside_rect.bottom = window_rect.bottom;
}
HDC dc = GetDC(hwnd);
{
SelectObject(dc, GetStockObject(DC_PEN));
SelectObject(dc, GetStockObject(DC_BRUSH));
RECT inside_rect; // Window border
inside_rect.top = window_rect.top + caption_width;
if (!IsZoomed(hwnd)){
inside_rect.left = window_rect.left + border_width;
inside_rect.right = window_rect.right - border_width;
inside_rect.bottom = window_rect.bottom - border_width;
}
else{
inside_rect.left = window_rect.left;
inside_rect.right = window_rect.right;
inside_rect.bottom = window_rect.bottom;
}
HDC dc = GetDC(hwnd);
{ {
SelectObject(dc, GetStockObject(DC_PEN)); if (WindowIsActive()){
SelectObject(dc, GetStockObject(DC_BRUSH)); SetDCPenColor(dc, RGB(255, 200, 0));
SetDCBrushColor(dc, RGB(255, 200, 0));
// Window border }
{ else{
if (WindowIsActive()){ SetDCPenColor(dc, RGB(128, 100, 0));
SetDCPenColor(dc, RGB(255, 200, 0)); SetDCBrushColor(dc, RGB(128, 100, 0));
SetDCBrushColor(dc, RGB(255, 200, 0)); }
}
else{ Rectangle(dc, window_rect.left, window_rect.top, window_rect.right, inside_rect.top);
SetDCPenColor(dc, RGB(128, 100, 0)); Rectangle(dc, window_rect.left, inside_rect.bottom, window_rect.right, window_rect.bottom);
SetDCBrushColor(dc, RGB(128, 100, 0)); Rectangle(dc, window_rect.left, inside_rect.top, inside_rect.left, inside_rect.bottom);
} Rectangle(dc, inside_rect.right, inside_rect.top, window_rect.right, inside_rect.bottom);
Rectangle(dc, window_rect.left, window_rect.top, window_rect.right, inside_rect.top);
Rectangle(dc, window_rect.left, inside_rect.bottom, window_rect.right, window_rect.bottom);
Rectangle(dc, window_rect.left, inside_rect.top, inside_rect.left, inside_rect.bottom);
Rectangle(dc, inside_rect.right, inside_rect.top, window_rect.right, inside_rect.bottom);
}
// Close button
if (window_rect.right > 20){
RECT button;
button.left = window_rect.right - 20;
button.top = window_rect.top + 10;
button.right = window_rect.right - 10;
button.bottom = window_rect.top + 20;
SetDCPenColor(dc, RGB(180, 0, 0));
SetDCBrushColor(dc, RGB(180, 0, 0));
EmbeddedWidgetRect(button);
Rectangle(dc, button.left, button.top, button.right, button.bottom);
if (input != 0 && HitTest(input->mouse_x, input->mouse_y, button)){
if (HasEvent(input, InputEventKind_MouseLeftPress)){
click_started = Widget_Close;
}
if (click_started == Widget_Close && HasEvent(input, InputEventKind_MouseLeftRelease)){
StopRunning();
}
}
}
// Minimize button
if (window_rect.right > 40){
RECT button;
button.left = window_rect.right - 40;
button.top = window_rect.top + 10;
button.right = window_rect.right - 30;
button.bottom = window_rect.top + 20;
SetDCPenColor(dc, RGB(0, 0, 180));
SetDCBrushColor(dc, RGB(0, 0, 180));
EmbeddedWidgetRect(button);
Rectangle(dc, button.left, button.top, button.right, button.bottom);
if (input != 0 && HitTest(input->mouse_x, input->mouse_y, button)){
if (HasEvent(input, InputEventKind_MouseLeftPress)){
click_started = Widget_Minimize;
}
if (click_started == Widget_Minimize && HasEvent(input, InputEventKind_MouseLeftRelease)){
Minimize(hwnd);
}
}
}
// Maximize button
if (window_rect.right > 60){
RECT button;
button.left = window_rect.right - 60;
button.top = window_rect.top + 10;
button.right = window_rect.right - 50;
button.bottom = window_rect.top + 20;
SetDCPenColor(dc, RGB(0, 180, 0));
SetDCBrushColor(dc, RGB(0, 180, 0));
EmbeddedWidgetRect(button);
Rectangle(dc, button.left, button.top, button.right, button.bottom);
if (input != 0 && HitTest(input->mouse_x, input->mouse_y, button)){
if (HasEvent(input, InputEventKind_MouseLeftPress)){
click_started = Widget_Maximize;
}
if (click_started == Widget_Maximize && HasEvent(input, InputEventKind_MouseLeftRelease)){
ToggleMaximize(hwnd);
}
}
}
// Slider
if (window_rect.right > 200){
RECT track;
track.left = window_rect.right - 195;
track.top = window_rect.top + 14;
track.right = window_rect.right - 95;
track.bottom = window_rect.top + 16;
SetDCPenColor(dc, RGB(0, 0, 0));
SetDCBrushColor(dc, RGB(0, 0, 0));
Rectangle(dc, track.left, track.top, track.right, track.bottom);
RECT button;
button.left = window_rect.right - 200 + slider_x;
button.top = window_rect.top + 10;
button.right = window_rect.right - 190 + slider_x;
button.bottom = window_rect.top + 20;
SetDCPenColor(dc, RGB(100, 200, 200));
SetDCBrushColor(dc, RGB(100, 200, 200));
EmbeddedWidgetRect(button);
Rectangle(dc, button.left, button.top, button.right, button.bottom);
if (input != 0){
if (HitTest(input->mouse_x, input->mouse_y, button)){
if (HasEvent(input, InputEventKind_MouseLeftPress)){
click_started = Widget_Slider;
delta_from_mouse_x = slider_x - input->mouse_x;
}
}
if (click_started == Widget_Slider){
slider_x = delta_from_mouse_x + input->mouse_x;
if (slider_x < 0){
slider_x = 0;
}
if (slider_x > 100){
slider_x = 100;
}
}
}
}
if (input != 0 && !input->left){
click_started = Widget_None;
}
// Inside area
{
SetDCPenColor(dc, RGB(127, 127, 127));
SetDCBrushColor(dc, RGB(127, 127, 127));
Rectangle(dc, inside_rect.left, inside_rect.top, inside_rect.right, inside_rect.bottom);
}
} }
ReleaseDC(hwnd, dc);
// Close button
if (window_rect.right > 20){
RECT button;
button.left = window_rect.right - 20;
button.top = window_rect.top + 10;
button.right = window_rect.right - 10;
button.bottom = window_rect.top + 20;
SetDCPenColor(dc, RGB(180, 0, 0));
SetDCBrushColor(dc, RGB(180, 0, 0));
EmbeddedWidgetRect(button);
Rectangle(dc, button.left, button.top, button.right, button.bottom);
if (input != 0 && HitTest(input->mouse_x, input->mouse_y, button)){
if (HasEvent(input, InputEventKind_MouseLeftPress)){
click_started = Widget_Close;
}
if (click_started == Widget_Close && HasEvent(input, InputEventKind_MouseLeftRelease)){
StopRunning();
}
}
}
// Minimize button
if (window_rect.right > 40){
RECT button;
button.left = window_rect.right - 40;
button.top = window_rect.top + 10;
button.right = window_rect.right - 30;
button.bottom = window_rect.top + 20;
SetDCPenColor(dc, RGB(0, 0, 180));
SetDCBrushColor(dc, RGB(0, 0, 180));
EmbeddedWidgetRect(button);
Rectangle(dc, button.left, button.top, button.right, button.bottom);
if (input != 0 && HitTest(input->mouse_x, input->mouse_y, button)){
if (HasEvent(input, InputEventKind_MouseLeftPress)){
click_started = Widget_Minimize;
}
if (click_started == Widget_Minimize && HasEvent(input, InputEventKind_MouseLeftRelease)){
Minimize(hwnd);
}
}
}
// Maximize button
if (window_rect.right > 60){
RECT button;
button.left = window_rect.right - 60;
button.top = window_rect.top + 10;
button.right = window_rect.right - 50;
button.bottom = window_rect.top + 20;
SetDCPenColor(dc, RGB(0, 180, 0));
SetDCBrushColor(dc, RGB(0, 180, 0));
EmbeddedWidgetRect(button);
Rectangle(dc, button.left, button.top, button.right, button.bottom);
if (input != 0 && HitTest(input->mouse_x, input->mouse_y, button)){
if (HasEvent(input, InputEventKind_MouseLeftPress)){
click_started = Widget_Maximize;
}
if (click_started == Widget_Maximize && HasEvent(input, InputEventKind_MouseLeftRelease)){
ToggleMaximize(hwnd);
}
}
}
// Slider
if (window_rect.right > 200){
RECT track;
track.left = window_rect.right - 195;
track.top = window_rect.top + 14;
track.right = window_rect.right - 95;
track.bottom = window_rect.top + 16;
SetDCPenColor(dc, RGB(0, 0, 0));
SetDCBrushColor(dc, RGB(0, 0, 0));
Rectangle(dc, track.left, track.top, track.right, track.bottom);
RECT button;
button.left = window_rect.right - 200 + slider_x;
button.top = window_rect.top + 10;
button.right = window_rect.right - 190 + slider_x;
button.bottom = window_rect.top + 20;
SetDCPenColor(dc, RGB(100, 200, 200));
SetDCBrushColor(dc, RGB(100, 200, 200));
EmbeddedWidgetRect(button);
Rectangle(dc, button.left, button.top, button.right, button.bottom);
if (input != 0){
if (HitTest(input->mouse_x, input->mouse_y, button)){
if (HasEvent(input, InputEventKind_MouseLeftPress)){
click_started = Widget_Slider;
delta_from_mouse_x = slider_x - input->mouse_x;
}
}
if (click_started == Widget_Slider){
slider_x = delta_from_mouse_x + input->mouse_x;
if (slider_x < 0){
slider_x = 0;
}
if (slider_x > 100){
slider_x = 100;
}
}
}
}
if (input != 0 && !input->left){
click_started = Widget_None;
}
// Inside area
{
SetDCPenColor(dc, RGB(127, 127, 127));
SetDCBrushColor(dc, RGB(127, 127, 127));
Rectangle(dc, inside_rect.left, inside_rect.top, inside_rect.right, inside_rect.bottom);
}
}
ReleaseDC(hwnd, dc);
} }