ulib/3party/rxcpp/Rx/v2/examples/win_text/main.cpp

245 lines
6.1 KiB
C++
Raw Normal View History

2024-01-10 09:33:36 +08:00
// win_text.cpp : Defines the entry point for the application.
//
//
#define STRICT
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <windowsx.h>
#include <ole2.h>
#include <commctrl.h>
#include <shlwapi.h>
#include <shlobj.h>
#include <shellapi.h>
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Ole32.lib")
#include <new>
#include <utility>
#include <memory>
#include <type_traits>
#include <tuple>
#include <list>
#include "rxcpp/rx.hpp"
// create alias' to simplify code
// these are owned by the user so that
// conflicts can be managed by the user.
namespace rx=rxcpp;
namespace rxsub=rxcpp::subjects;
namespace rxu=rxcpp::util;
// At this time, RxCpp will fail to compile if the contents
// of the std namespace are merged into the global namespace
// DO NOT USE: 'using namespace std;'
#include "unwinder.h"
#include "windows_user.h"
namespace wu = windows_user;
#include "rx_windows_user.h"
namespace rxwu = rxcpp::windows_user;
struct RootWindow : public rxwu::rx_messages, public rxwu::enable_send_call<RootWindow, WM_USER+1>
{
// window class
using window_class = wu::window_class<RootWindow>;
static LPCWSTR class_name() {return L"Scratch";}
static void change_class(WNDCLASSEX&) {}
// createstruct parameter type
using param_type = std::wstring;
// public methods
// static methods use a window message per call
static LRESULT set_title(HWND w, const std::wstring& t) {
return send_call(w, [&](RootWindow& r){
r.set_title(t);
return 0;
});
}
static std::wstring get_title(HWND w) {
std::wstring t;
send_call(w, [&](RootWindow& r){
t = r.get_title();
return 0;
});
return t;
}
// instance methods are accessed using static send_call(hwnd, [](RootWindow& r){. . .});
// send_call uses one window message, the lambda can call many instance methods.
void set_title(const std::wstring& t) {
title = t;
}
const std::wstring& get_title() {
return title;
}
// lifetime
// called during WM_NCDESTROY
~RootWindow() {
PostQuitMessage(0);
}
// called during WM_NCCREATE
RootWindow(HWND w, LPCREATESTRUCT, param_type* title)
: window(w)
, title(title ? *title : L"RootWindow")
, position{40, 10} {
// listen for the following messages
OnPaint();
OnPrintClient();
OnKeyDown();
OnMovesWhileLButtonDown();
}
private:
// implementation
HWND window;
std::wstring title;
POINTS position;
void PaintContent(PAINTSTRUCT& ps) {
RECT rect;
GetClientRect (window, &rect) ;
SetTextColor(ps.hdc, 0x00000000);
SetBkMode(ps.hdc,TRANSPARENT);
rect.left=position.x;
rect.top=position.y;
DrawText( ps.hdc, title.c_str(), -1, &rect, DT_SINGLELINE | DT_NOCLIP ) ;
}
void OnKeyDown() {
messages<WM_KEYDOWN>().
subscribe([this](auto m) {
m.handled(); // skip DefWindowProc
MessageBox(window, L"KeyDown", L"RootWindow", MB_OK);
// NOTE: MessageBox pumps messages, but this subscription only
// receives messages if it is suspended by 'for await', so any
// WM_KEYDOWN arriving while the message box is up is not delivered.
// the other subscriptions will receive messages.
});
}
void OnMovesWhileLButtonDown() {
auto moves_while_lbutton_down = messages<WM_LBUTTONDOWN>().
map(
[this](auto m) {
m.handled(); // skip DefWindowProc
return this->messages<WM_MOUSEMOVE>().
take_until(this->messages<WM_LBUTTONUP>());
}).
merge();
moves_while_lbutton_down.
subscribe([this](auto m) {
m.handled(); // skip DefWindowProc
position = MAKEPOINTS(m.lParam);
InvalidateRect(window, nullptr, true);
});
}
void OnPaint() {
messages<WM_PAINT>().
subscribe([this](auto m) {
m.handled(); // skip DefWindowProc
PAINTSTRUCT ps;
BeginPaint(window, &ps);
PaintContent(ps);
EndPaint(window, &ps);
});
}
void OnPrintClient() {
messages<WM_PRINTCLIENT, HDC>().
subscribe([this](auto m) {
m.handled(); // skip DefWindowProc
PAINTSTRUCT ps;
ps.hdc = m.wParam;
GetClientRect(window, &ps.rcPaint);
PaintContent(ps);
});
}
};
int PASCAL
wWinMain(HINSTANCE hinst, HINSTANCE, LPWSTR, int nShowCmd)
{
HRESULT hr = S_OK;
hr = CoInitialize(NULL);
if (FAILED(hr))
{
return FALSE;
}
ON_UNWIND_AUTO([&]{CoUninitialize();});
InitCommonControls();
RootWindow::window_class::Register();
LONG winerror = ERROR_SUCCESS;
std::wstring title{L"Scratch App - RootWindow"};
// normal create window call, just takes the class name and optional create parameters
HWND window = CreateWindow(
RootWindow::window_class::Name(), title.c_str(),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL,
hinst,
&title);
if (!window) {winerror = GetLastError();}
if (!!winerror || !window)
{
return winerror;
}
ShowWindow(window, nShowCmd);
// interact with window safely on the UI thread from another thread
auto settitle = std::async([window](){
// by static method (two SendMessage)
RootWindow::set_title(window, L"SET_TITLE! " + RootWindow::get_title(window));
// or multiple instance methods (one SendMessage)
RootWindow::send_call(window, [](RootWindow& r){
r.set_title(L"SEND_CALL! " + r.get_title());
return 0;
});
});
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
settitle.get();
return 0;
}