Import Geant4 11.0.0.beta source tree
This commit is contained in:
@@ -0,0 +1,810 @@
|
||||
// Copyright (C) 2010, Guy Barrand. All rights reserved.
|
||||
// See the file tools.license for terms.
|
||||
|
||||
#ifndef tools_Windows_WinTk
|
||||
#define tools_Windows_WinTk
|
||||
|
||||
#include "../Windows/tools" //and not "tools", because this fancy VisualC++ will not find the file!
|
||||
|
||||
#include <tools/touplow>
|
||||
#include <tools/words>
|
||||
#ifdef TOOLS_MEM
|
||||
#include <tools/mem>
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace tools {
|
||||
namespace WinTk {
|
||||
|
||||
class Component;
|
||||
|
||||
class CallbackData {
|
||||
public:
|
||||
CallbackData():x(0),y(0),wparam(0),lparam(0){}
|
||||
public:
|
||||
std::string value;
|
||||
int x;
|
||||
int y;
|
||||
WPARAM wparam;
|
||||
LPARAM lparam;
|
||||
};
|
||||
|
||||
typedef void (*Callback)(Component&,CallbackData&,void*);
|
||||
|
||||
class Component {
|
||||
typedef std::vector< std::pair<Callback,void*> > Callbacks;
|
||||
typedef std::pair<std::string,Callbacks> NamedCallbacks;
|
||||
#ifdef TOOLS_MEM
|
||||
TOOLS_SCLASS(tools::WinTk::Component)
|
||||
#endif
|
||||
public:
|
||||
Component(const std::string& aType):fType(aType),fWindow(0),fParent(0){
|
||||
#ifdef TOOLS_MEM
|
||||
tools::mem::increment(s_class().c_str());
|
||||
#endif
|
||||
}
|
||||
Component(const std::string& aType,Component& aParent):fType(aType),fWindow(0),fParent(&aParent) {
|
||||
#ifdef TOOLS_MEM
|
||||
tools::mem::increment(s_class().c_str());
|
||||
#endif
|
||||
}
|
||||
virtual ~Component() {
|
||||
#ifdef TOOLS_MEM
|
||||
tools::mem::decrement(s_class().c_str());
|
||||
#endif
|
||||
}
|
||||
protected:
|
||||
Component(Component&) {
|
||||
#ifdef TOOLS_MEM
|
||||
tools::mem::increment(s_class().c_str());
|
||||
#endif
|
||||
}
|
||||
Component& operator=(Component&) {return *this;}
|
||||
public:
|
||||
std::string name() const {return fName;}
|
||||
void setName(const std::string& aName) {fName = aName;}
|
||||
|
||||
const std::string& type() const {return fType;}
|
||||
HWND nativeWindow() {return fWindow;}
|
||||
Component* parent() const {return fParent;}
|
||||
virtual void show() {
|
||||
//if(!fWindow) return;
|
||||
//::ShowWindow(fWindow,SW_SHOWDEFAULT);
|
||||
}
|
||||
void hide() {
|
||||
if(!fWindow) return;
|
||||
::ShowWindow(fWindow,SW_HIDE);
|
||||
}
|
||||
|
||||
virtual bool size(unsigned int& aWidth,unsigned int& aHeight) {
|
||||
aWidth = 0;
|
||||
aHeight = 0;
|
||||
if(!fWindow) return false;
|
||||
RECT rect;
|
||||
::GetClientRect(fWindow,&rect);
|
||||
aWidth = rect.right-rect.left;
|
||||
aHeight = rect.bottom-rect.top;
|
||||
return true;
|
||||
}
|
||||
virtual bool position(int& aX,int& aY) {
|
||||
aX = 0;
|
||||
aY = 0;
|
||||
if(!fWindow) return false;
|
||||
RECT rect;
|
||||
::GetClientRect(fWindow,&rect);
|
||||
aX = rect.left;
|
||||
aY = rect.top;
|
||||
return true;
|
||||
}
|
||||
Component* findFather(const std::string& aType) {
|
||||
if(aType==type()) return this;
|
||||
Component* parent = fParent;
|
||||
while(parent) {
|
||||
if(aType==parent->type()) return parent;
|
||||
parent = parent->fParent;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool setBackground(double aR,double aG,double aB){
|
||||
if(!fWindow) return false;
|
||||
|
||||
int r = int(aR*255.0);
|
||||
if((r<0)||(r>255)) return false;
|
||||
int g = int(aG*255.0);
|
||||
if((g<0)||(g>255)) return false;
|
||||
int b = int(aB*255.0);
|
||||
if((b<0)||(b>255)) return false;
|
||||
|
||||
/*
|
||||
//COLORREF cr = RGB(r,g,b);
|
||||
HBRUSH brush = ::CreateSolidBrush(RGB(r,g,b));
|
||||
::printf("debug : WinTk::Component::setBackground : brush %lu\n",brush);
|
||||
|
||||
HBRUSH prev = (HBRUSH)::GetClassLongPtr(fWindow,GCLP_HBRBACKGROUND);
|
||||
::printf("debug : WinTk::Component::setBackground : prev brush %lu\n",prev);
|
||||
|
||||
{WNDCLASSEX wc;
|
||||
::GetClassInfoEx(::GetModuleHandle(NULL),WC_STATIC,&wc);
|
||||
::printf("debug : prev brush xxx %lu\n",wc.hbrBackground);}
|
||||
|
||||
ULONG_PTR stat =
|
||||
::SetClassLongPtr(fWindow,GCLP_HBRBACKGROUND,(LONG_PTR)brush);
|
||||
if(prev && !stat) {
|
||||
::printf("debug : WinTk::Component::setBackground : SetClassLongPtr failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
{ULONG_PTR stat =
|
||||
::SetClassLongPtr(fWindow,GCLP_HBRBACKGROUND,(LONG_PTR)brush);
|
||||
::printf("debug : WinTk::Component::setBackground : SetClassLongPtr failed.yyy %lu.\n",stat);}
|
||||
|
||||
{WNDCLASSEX wc;
|
||||
::GetClassInfoEx(::GetModuleHandle(NULL),WC_STATIC,&wc);
|
||||
::printf("debug : prev brush yyy %lu\n",wc.hbrBackground);}
|
||||
|
||||
if(!::InvalidateRect(fWindow,NULL,TRUE)) {
|
||||
::printf("debug : WinTk::Component::setBackground : InvalidateRect failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
//::DeleteObject(brush);
|
||||
return true;
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
public:
|
||||
void addCallback(const std::string& aName,Callback aFunction,void* aTag) {
|
||||
NamedCallbacks* cbks = 0;
|
||||
std::vector<NamedCallbacks>::iterator it;
|
||||
for(it=fCallbacks.begin();it!=fCallbacks.end();++it) {
|
||||
if(aName==(*it).first) {
|
||||
cbks = &(*it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!cbks) {
|
||||
fCallbacks.push_back(std::pair<std::string,Callbacks>(aName,Callbacks()));
|
||||
cbks = &(fCallbacks.back());
|
||||
}
|
||||
cbks->second.push_back(std::pair<Callback,void*>(aFunction,aTag));
|
||||
}
|
||||
void removeCallback(const std::string& aName,Callback aFunction,void* aTag) {
|
||||
NamedCallbacks* cbks = 0;
|
||||
std::vector<NamedCallbacks>::iterator it;
|
||||
for(it=fCallbacks.begin();it!=fCallbacks.end();++it) {
|
||||
if(aName==(*it).first) {
|
||||
cbks = &(*it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(cbks) {
|
||||
Callbacks::iterator it;
|
||||
for(it=cbks->second.begin();it!=cbks->second.end();++it) {
|
||||
if( (aFunction==(*it).first) && (aTag==(*it).second) ) {
|
||||
cbks->second.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool executeCallbacks(const std::string& aName,CallbackData& aData) {
|
||||
std::vector<NamedCallbacks>::const_iterator it;
|
||||
for(it=fCallbacks.begin();it!=fCallbacks.end();++it) {
|
||||
if(aName==(*it).first) {
|
||||
const Callbacks& cbks = (*it).second;
|
||||
Callbacks::const_iterator it2;
|
||||
for(it2=cbks.begin();it2!=cbks.end();++it2) {
|
||||
Callback cbk = (*it2).first;
|
||||
if(cbk) {
|
||||
HWND back_fWindow = fWindow;
|
||||
cbk(*this,aData,(*it2).second);
|
||||
// The callback may have destroyed the Component and
|
||||
// the native HWND. The below checks that.
|
||||
// In a proc, it is better to not use the HWND
|
||||
// (or the Component) after calling executeCallbacks.
|
||||
if(back_fWindow && !::GetWindowLongPtr(back_fWindow,GWLP_USERDATA)) {
|
||||
//::printf("WinTk::Component::executeCallbacks : WARNING : A callback destroyed the native HWND window !\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool hasCallbacks(const std::string& aName) const {
|
||||
std::vector<NamedCallbacks>::const_iterator it;
|
||||
for(it=fCallbacks.begin();it!=fCallbacks.end();++it) {
|
||||
if(aName==(*it).first) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
protected:
|
||||
static void wm__destroy(HWND aWindow) {
|
||||
Component* This = (Component*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
|
||||
if(This) { //How to be sure that we have a Component* ???
|
||||
if(This->fWindow!=aWindow) {
|
||||
::printf("WinTk::Component::wm_destroy : HWND mismatch !\n");
|
||||
}
|
||||
if(This->hasCallbacks("WM_DESTROY")) {
|
||||
CallbackData data;
|
||||
This->executeCallbacks("WM_DESTROY",data);
|
||||
}
|
||||
This->fWindow = 0;
|
||||
}
|
||||
::SetWindowLongPtr(aWindow,GWLP_USERDATA,LONG_PTR(NULL));
|
||||
}
|
||||
protected:
|
||||
// WM_PARENTNOTIFY is sent within the CreateWindow of the child.
|
||||
// When received by the parent, the parent Post (not Send) to itself
|
||||
// a WM_TK_CHILDCREATED in order to be notify of the child creation
|
||||
// out of any CreateWindow.
|
||||
#define WM_TK_CHILDCREATED ((WM_USER)+888)
|
||||
#define WM_TK_CHILDDELETED ((WM_USER)+889)
|
||||
#define TK_KEY 127 // To be sure that it is a message of our own.
|
||||
static LRESULT CALLBACK containerProc(HWND aWindow,UINT aMessage,WPARAM aWParam,LPARAM aLParam) {
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Some child send notification message to their parent (instead of sending
|
||||
// the message to themselves !). This procedure is used by containers
|
||||
// to forward these messages to the child.
|
||||
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
|
||||
switch(aMessage) {
|
||||
case WM_PARENTNOTIFY:{
|
||||
if(aWParam==WM_CREATE) {
|
||||
::PostMessage(aWindow,WM_TK_CHILDCREATED,TK_KEY,0);
|
||||
return 0;
|
||||
} else if(aWParam==WM_DESTROY) {
|
||||
::PostMessage(aWindow,WM_TK_CHILDDELETED,TK_KEY,0);
|
||||
return 0;
|
||||
}
|
||||
}break;
|
||||
case WM_TK_CHILDCREATED:{
|
||||
if(aWParam==TK_KEY) {
|
||||
RECT rect;
|
||||
::GetClientRect(aWindow,&rect);
|
||||
LPARAM size = MAKELPARAM(rect.right-rect.left,rect.bottom-rect.top);
|
||||
::SendMessage(aWindow,WM_SIZE,(WPARAM)0,size);
|
||||
return 0;
|
||||
}
|
||||
}break;
|
||||
case WM_TK_CHILDDELETED:{
|
||||
if(aWParam==TK_KEY) {
|
||||
}
|
||||
}break;
|
||||
case WM_NOTIFY:{ //Coming from a child (combobox, scrollbar, toolbar).
|
||||
NMHDR* nmhdr = (NMHDR*)aLParam;
|
||||
HWND from_win = nmhdr->hwndFrom;
|
||||
if(from_win!=aWindow) {
|
||||
::SendMessage(from_win,aMessage,aWParam,aLParam);
|
||||
}
|
||||
}return 0;
|
||||
case WM_COMMAND:
|
||||
case WM_VSCROLL:
|
||||
case WM_HSCROLL:{
|
||||
::SendMessage((HWND)aLParam,aMessage,aWParam,(LPARAM)0);
|
||||
}return 0;
|
||||
}
|
||||
return TRUE; //Not handled.
|
||||
}
|
||||
#undef WM_TK_CHILDCREATED
|
||||
#undef WM_TK_CHILDDELETED
|
||||
#undef TK_KEY
|
||||
protected:
|
||||
void destroy() {
|
||||
if(hasCallbacks("delete")) {
|
||||
CallbackData data;
|
||||
executeCallbacks("delete",data);
|
||||
}
|
||||
if(fWindow) {
|
||||
::SetWindowLongPtr(fWindow,GWLP_USERDATA,LONG_PTR(NULL));
|
||||
::DestroyWindow(fWindow);
|
||||
fWindow = 0;
|
||||
}
|
||||
}
|
||||
void rubberDrawLine(POINT& aBegin,POINT& aEnd) {
|
||||
if(!fWindow) return;
|
||||
HPEN pen = ::CreatePen(PS_SOLID,5,RGB(0,0,0));
|
||||
HDC hdc = ::GetWindowDC(fWindow);
|
||||
HPEN oldPen = SelectPen(hdc,pen);
|
||||
int oldROP = ::SetROP2(hdc,R2_NOT);
|
||||
POINT pt;
|
||||
::MoveToEx(hdc,aBegin.x,aBegin.y,&pt);
|
||||
::LineTo(hdc,aEnd.x,aEnd.y);
|
||||
::SetROP2(hdc,oldROP);
|
||||
SelectPen(hdc,oldPen);
|
||||
::ReleaseDC(fWindow,hdc);
|
||||
::DeletePen(pen);
|
||||
}
|
||||
void rubberDrawRect(POINT& aBegin,POINT& aEnd) {
|
||||
if(!fWindow) return;
|
||||
HPEN pen = ::CreatePen(PS_SOLID,0,RGB(0,0,0));
|
||||
HDC hdc = ::GetWindowDC(fWindow);
|
||||
HPEN oldPen = SelectPen(hdc,pen);
|
||||
int oldROP = ::SetROP2(hdc,R2_NOT);
|
||||
POINT pt;
|
||||
::MoveToEx(hdc,aBegin.x,aBegin.y,&pt);
|
||||
::LineTo(hdc,aBegin.x,aEnd.y);
|
||||
::LineTo(hdc,aEnd.x,aEnd.y);
|
||||
::LineTo(hdc,aEnd.x,aBegin.y);
|
||||
::LineTo(hdc,aBegin.x,aBegin.y);
|
||||
::SetROP2(hdc,oldROP);
|
||||
SelectPen(hdc,oldPen);
|
||||
::ReleaseDC(fWindow,hdc);
|
||||
::DeletePen(pen);
|
||||
}
|
||||
private:
|
||||
std::string fType;
|
||||
protected:
|
||||
HWND fWindow;
|
||||
Component* fParent;
|
||||
std::vector<NamedCallbacks> fCallbacks;
|
||||
std::string fName;
|
||||
};
|
||||
|
||||
class Shell;
|
||||
typedef void(*SetFocusCallback)(Shell*,void*);
|
||||
|
||||
class Shell : public Component {
|
||||
public:
|
||||
Shell(unsigned int aMask)
|
||||
:Component("Shell")
|
||||
,fFocusWindow(0)
|
||||
,fSetFocusCallback(0)
|
||||
,fSetFocusTag(0)
|
||||
,fAcceleratorTable(0)
|
||||
{
|
||||
static char sWindowClassName[] = "WinTk::Shell";
|
||||
static bool done = false;
|
||||
if(!done) {
|
||||
WNDCLASS wc;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.lpfnWndProc = (WNDPROC)Shell::proc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = ::GetModuleHandle(NULL);
|
||||
wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
|
||||
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
|
||||
wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
|
||||
wc.lpszMenuName = sWindowClassName;
|
||||
wc.lpszClassName = sWindowClassName;
|
||||
::RegisterClass(&wc);
|
||||
done = true;
|
||||
}
|
||||
|
||||
fWindow = ::CreateWindow(sWindowClassName,
|
||||
NULL,
|
||||
aMask, //WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT,CW_USEDEFAULT,
|
||||
400,400,
|
||||
NULL,NULL,
|
||||
::GetModuleHandle(NULL),
|
||||
NULL);
|
||||
if(!fWindow) return;
|
||||
::SetWindowLongPtr(fWindow,GWLP_USERDATA,LONG_PTR(this));
|
||||
}
|
||||
virtual ~Shell() {
|
||||
if(fAcceleratorTable) {
|
||||
::DestroyAcceleratorTable(fAcceleratorTable);
|
||||
fAcceleratorTable = 0;
|
||||
}
|
||||
destroy();
|
||||
}
|
||||
protected:
|
||||
Shell(Shell& a_from):Component(a_from) {}
|
||||
Shell& operator=(Shell&) {return *this;}
|
||||
public:
|
||||
virtual void show() {
|
||||
if(!fWindow) return;
|
||||
::SetForegroundWindow(fWindow);
|
||||
::ShowWindow(fWindow,SW_SHOWDEFAULT);
|
||||
::UpdateWindow(fWindow);
|
||||
::DrawMenuBar(fWindow);
|
||||
}
|
||||
void setTitle(const std::string& aString) {
|
||||
if(!fWindow) return;
|
||||
::SetWindowText(fWindow,aString.c_str());
|
||||
}
|
||||
void setGeometry(int aX,int aY,unsigned int aWidth,unsigned int aHeight) {
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Given width, height is the desired client area.
|
||||
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
|
||||
if(!fWindow) return;
|
||||
int hborder = ::GetSystemMetrics(SM_CYCAPTION);
|
||||
if(::GetWindowLongPtr(fWindow,GWLP_ID)) // Has a menubar.
|
||||
hborder += ::GetSystemMetrics(SM_CYMENU);
|
||||
::MoveWindow(fWindow,aX,aY,aWidth,hborder + aHeight,TRUE);
|
||||
}
|
||||
void setSize(unsigned int aWidth,unsigned int aHeight) {
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Given width, height is the desired client area.
|
||||
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
|
||||
if(!fWindow) return;
|
||||
int hborder = ::GetSystemMetrics(SM_CYCAPTION);
|
||||
RECT rect;
|
||||
::GetWindowRect(fWindow,&rect);
|
||||
::MoveWindow(fWindow,rect.left,rect.top,aWidth,hborder + aHeight,TRUE);
|
||||
}
|
||||
void setFocusWindow(HWND aWindow) {fFocusWindow = aWindow;}
|
||||
HWND focusWindow() {return fFocusWindow;}
|
||||
|
||||
void setSetFocusCallback(SetFocusCallback aCallback,void* aTag) {
|
||||
fSetFocusCallback = aCallback;
|
||||
fSetFocusTag = aTag;
|
||||
}
|
||||
void callSetFocusCallback() {
|
||||
if(!fSetFocusCallback) return;
|
||||
fSetFocusCallback(this,fSetFocusTag);
|
||||
}
|
||||
HACCEL nativeAcceleratorTable() {return fAcceleratorTable;}
|
||||
|
||||
bool addAccelerator(const std::string& aString,int aID) {
|
||||
//printf("debug : accel : %s %d\n",aString.c_str(),aID);
|
||||
// aString should be of the form : "a" or "Ctrl+a".
|
||||
ACCEL acc;
|
||||
//acc.fVirt : FALT, FCONTROL, FNOINVERT, FSHIFT, FVIRTKEY
|
||||
{acc.cmd = aID;
|
||||
std::vector<std::string> words;
|
||||
std::string s(aString);
|
||||
tools::touppercase(s);
|
||||
tools::words(s,"+",false,words);
|
||||
if(words.size()==1) {
|
||||
acc.fVirt = FVIRTKEY;
|
||||
if(!string_to_VK(words[0],acc.key)) return false;
|
||||
} else if((words.size()==2)&&(words[1].size())) {
|
||||
if(words[0]=="CTRL") {
|
||||
acc.fVirt = FCONTROL;
|
||||
} else if(words[0]=="ALT") {
|
||||
acc.fVirt = FALT;
|
||||
} else if(words[0]=="SHIFT") {
|
||||
acc.fVirt = FSHIFT;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
acc.fVirt |= FVIRTKEY;
|
||||
if(!string_to_VK(words[1],acc.key)) return false;
|
||||
} else {
|
||||
return false;
|
||||
}}
|
||||
|
||||
if(!fAcceleratorTable) {
|
||||
fAcceleratorTable = ::CreateAcceleratorTable(&acc,1);
|
||||
} else {
|
||||
int n = ::CopyAcceleratorTable(fAcceleratorTable,NULL,0);
|
||||
ACCEL* tbl = new ACCEL[n+1];
|
||||
::CopyAcceleratorTable(fAcceleratorTable,tbl,n);
|
||||
ACCEL& tacc = tbl[n];
|
||||
tacc.fVirt = acc.fVirt;
|
||||
tacc.key = acc.key;
|
||||
tacc.cmd = acc.cmd;
|
||||
::DestroyAcceleratorTable(fAcceleratorTable);
|
||||
fAcceleratorTable = ::CreateAcceleratorTable(tbl,n+1);
|
||||
delete [] tbl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
|
||||
static bool string_to_VK(const std::string& aString,WORD& a_VK) {
|
||||
//VK_xxx are defined in WinUser.h
|
||||
if(aString.size()==1) { a_VK = aString[0];return true;} //WM_W is 'W'
|
||||
|
||||
#define S_VK(aWhat) \
|
||||
if(!::strcmp(aString.c_str(),#aWhat)) { a_VK = VK_##aWhat;return true;}
|
||||
|
||||
S_VK(BACK)
|
||||
S_VK(TAB)
|
||||
S_VK(CLEAR)
|
||||
S_VK(RETURN)
|
||||
S_VK(ESCAPE)
|
||||
S_VK(SPACE)
|
||||
|
||||
S_VK(UP)
|
||||
S_VK(DOWN)
|
||||
S_VK(LEFT)
|
||||
S_VK(RIGHT)
|
||||
|
||||
S_VK(F1)
|
||||
S_VK(F2)
|
||||
S_VK(F3)
|
||||
S_VK(F4)
|
||||
S_VK(F5)
|
||||
S_VK(F6)
|
||||
S_VK(F7)
|
||||
S_VK(F8)
|
||||
S_VK(F9)
|
||||
S_VK(F10)
|
||||
S_VK(F11)
|
||||
S_VK(F12)
|
||||
S_VK(F13)
|
||||
S_VK(F14)
|
||||
S_VK(F15)
|
||||
S_VK(F16)
|
||||
S_VK(F17)
|
||||
S_VK(F18)
|
||||
S_VK(F19)
|
||||
S_VK(F20)
|
||||
S_VK(F21)
|
||||
S_VK(F22)
|
||||
S_VK(F23)
|
||||
S_VK(F24)
|
||||
|
||||
//FIXME : handle other keys ? NUMPAD[0-9]
|
||||
|
||||
#undef S_VK
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK proc(HWND aWindow,UINT aMessage,WPARAM aWParam,LPARAM aLParam) {
|
||||
switch (aMessage) {
|
||||
// Same logic as containerProc :
|
||||
case WM_NOTIFY:{ //Coming from a child (combobox, scrollbar, toolbar).
|
||||
NMHDR* nmhdr = (NMHDR*)aLParam;
|
||||
HWND from_win = nmhdr->hwndFrom;
|
||||
if(from_win!=aWindow) {
|
||||
::SendMessage(from_win,aMessage,aWParam,aLParam);
|
||||
}
|
||||
}return 0;
|
||||
// Else :
|
||||
case WM_SIZE:{ // Assume one child window ! FIXME : have a message if not.
|
||||
int width = LOWORD(aLParam);
|
||||
int height = HIWORD(aLParam);
|
||||
HWND hwnd = GetFirstChild(aWindow);
|
||||
if(hwnd) {
|
||||
//FIXME : have to treat the case of TOOLBAR not being the first.
|
||||
if(GetClassName(hwnd)==std::string(TOOLBARCLASSNAME)) {
|
||||
HWND next = GetNextSibling(hwnd);
|
||||
// Share area between toolbar and second child :
|
||||
RECT rect;
|
||||
::GetWindowRect(hwnd,&rect);
|
||||
int htb = rect.bottom-rect.top;
|
||||
SetGeometry(next,0,htb,width,height-htb);
|
||||
} else {
|
||||
SetGeometry(hwnd,0,0,width,height);
|
||||
}
|
||||
}
|
||||
}return 0;
|
||||
case WM_SETFOCUS:{
|
||||
Shell* This = (Shell*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
|
||||
if(This) {
|
||||
This->callSetFocusCallback();
|
||||
HWND win = This->focusWindow();
|
||||
if(win) ::SetFocus(win);
|
||||
}
|
||||
}return 0;
|
||||
case WM_INITMENUPOPUP:{ //0x0117
|
||||
//aWParam is the HMENU (from CreatePopupMenu)
|
||||
//aLParam is the MenuItemCount
|
||||
Shell* This = (Shell*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
|
||||
if(This) {
|
||||
CallbackData data;
|
||||
data.wparam = aWParam;
|
||||
This->executeCallbacks("cascading",data);
|
||||
}
|
||||
} return 0;
|
||||
case WM_COMMAND:{ //Coming from a menu item, a toolbar !
|
||||
if(aLParam) {
|
||||
// From a toolbar ; send it back to it :
|
||||
::SendMessage((HWND)aLParam,aMessage,aWParam,0);
|
||||
} else {
|
||||
//if(HIWORD(aWParam)==1) { //From an accelerator.
|
||||
//}
|
||||
// From a menu item :
|
||||
Shell* This = (Shell*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
|
||||
if(This) {
|
||||
CallbackData data;
|
||||
data.wparam = LOWORD(aWParam);
|
||||
This->executeCallbacks("activate",data);
|
||||
}
|
||||
}
|
||||
}return 0;
|
||||
case WM_CLOSE:{
|
||||
Shell* This = (Shell*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
|
||||
if(This) {
|
||||
if(This->hasCallbacks("close")) {
|
||||
CallbackData data;
|
||||
This->executeCallbacks("close",data);
|
||||
}
|
||||
}
|
||||
}break; //NOTE : can't be return 0.
|
||||
case WM_DESTROY:wm__destroy(aWindow);return 0;
|
||||
}
|
||||
return (DefWindowProc(aWindow,aMessage,aWParam,aLParam));
|
||||
}
|
||||
private:
|
||||
HWND fFocusWindow;
|
||||
SetFocusCallback fSetFocusCallback;
|
||||
void* fSetFocusTag;
|
||||
HACCEL fAcceleratorTable;
|
||||
};
|
||||
|
||||
class OpenGLArea : public Component {
|
||||
public:
|
||||
OpenGLArea(Component& aParent)
|
||||
:Component("OpenGLArea",aParent)
|
||||
,fContext(0)
|
||||
,fHDC(0)
|
||||
{
|
||||
if(!fParent || !fParent->nativeWindow()) return;
|
||||
HWND parent = fParent->nativeWindow();
|
||||
|
||||
static char sOpenGLAreaClassName[] = "WinTk::OpenGLArea";
|
||||
static bool done = false;
|
||||
if(!done) {
|
||||
WNDCLASS wc;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.lpfnWndProc = (WNDPROC)OpenGLArea::proc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = GetWindowInstance(parent),
|
||||
wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
|
||||
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
|
||||
wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
|
||||
wc.lpszMenuName = sOpenGLAreaClassName;
|
||||
wc.lpszClassName = sOpenGLAreaClassName;
|
||||
::RegisterClass(&wc);
|
||||
done = true;
|
||||
}
|
||||
|
||||
// The WS_BORDER is needed. Else probleme of size at startup.
|
||||
RECT rect;
|
||||
::GetClientRect(parent,&rect);
|
||||
fWindow = ::CreateWindow(sOpenGLAreaClassName,
|
||||
NULL,
|
||||
WS_CHILD | WS_VISIBLE,
|
||||
0,0,
|
||||
rect.right-rect.left,
|
||||
rect.bottom-rect.top,
|
||||
parent,NULL,
|
||||
GetWindowInstance(parent),
|
||||
NULL);
|
||||
if(!fWindow) return;
|
||||
::SetWindowLongPtr(fWindow,GWLP_USERDATA,LONG_PTR(this));
|
||||
|
||||
// initialize OpenGL rendering :
|
||||
fHDC = ::GetDC(fWindow);
|
||||
if( fHDC && SetWindowPixelFormat(fHDC) ) {
|
||||
fContext = ::wglCreateContext(fHDC);
|
||||
}
|
||||
}
|
||||
virtual ~OpenGLArea() {
|
||||
if(wglGetCurrentContext()!=NULL) wglMakeCurrent(NULL,NULL);
|
||||
if(fContext) {
|
||||
wglDeleteContext(fContext);
|
||||
fContext = 0;
|
||||
}
|
||||
destroy();
|
||||
}
|
||||
protected:
|
||||
OpenGLArea(OpenGLArea& a_from):Component(a_from) {}
|
||||
OpenGLArea& operator=(OpenGLArea&) {return *this;}
|
||||
public:
|
||||
bool write_gl2ps(const std::string&,const std::string&);
|
||||
private:
|
||||
static LRESULT CALLBACK proc(HWND aWindow,UINT aMessage,WPARAM aWParam,LPARAM aLParam) {
|
||||
switch (aMessage) {
|
||||
case WM_PAINT:{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hDC = BeginPaint(aWindow,&ps);
|
||||
OpenGLArea* This = (OpenGLArea*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
|
||||
if(This) {
|
||||
HDC hdc = This->fHDC;
|
||||
HGLRC context = This->fContext;
|
||||
if(hdc && context) {
|
||||
::wglMakeCurrent(hdc,context);
|
||||
// User OpenGL paint code :
|
||||
|
||||
CallbackData data;
|
||||
data.wparam = aWParam;
|
||||
data.lparam = aLParam;
|
||||
This->executeCallbacks("paint",data);
|
||||
|
||||
::SwapBuffers(hdc);
|
||||
}
|
||||
}
|
||||
EndPaint(aWindow,&ps);
|
||||
}return 0;
|
||||
case WM_LBUTTONDOWN:{
|
||||
OpenGLArea* This = (OpenGLArea*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
|
||||
if(This) {
|
||||
CallbackData data;
|
||||
data.wparam = aWParam;
|
||||
data.lparam = aLParam;
|
||||
data.value = "ButtonPress";
|
||||
data.x = LOWORD(aLParam);
|
||||
data.y = HIWORD(aLParam);
|
||||
This->executeCallbacks("event",data);
|
||||
}
|
||||
}return 0;
|
||||
case WM_LBUTTONUP:{
|
||||
OpenGLArea* This = (OpenGLArea*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
|
||||
if(This) {
|
||||
CallbackData data;
|
||||
data.wparam = aWParam;
|
||||
data.lparam = aLParam;
|
||||
data.value = "ButtonRelease";
|
||||
data.x = LOWORD(aLParam);
|
||||
data.y = HIWORD(aLParam);
|
||||
This->executeCallbacks("event",data);
|
||||
}
|
||||
} return 0;
|
||||
case WM_MOUSEMOVE:{
|
||||
unsigned int state = aWParam;
|
||||
if((state & MK_LBUTTON)==MK_LBUTTON) {
|
||||
OpenGLArea* This = (OpenGLArea*)::GetWindowLongPtr(aWindow,GWLP_USERDATA);
|
||||
if(This) {
|
||||
CallbackData data;
|
||||
data.wparam = aWParam;
|
||||
data.lparam = aLParam;
|
||||
data.value = "MotionNotify";
|
||||
data.x = LOWORD(aLParam);
|
||||
data.y = HIWORD(aLParam);
|
||||
This->executeCallbacks("event",data);
|
||||
}
|
||||
}
|
||||
}return 0;
|
||||
case WM_DESTROY:wm__destroy(aWindow);return 0;
|
||||
}
|
||||
return (DefWindowProc(aWindow,aMessage,aWParam,aLParam));
|
||||
}
|
||||
static bool SetWindowPixelFormat(HDC aHdc) {
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags =
|
||||
PFD_DRAW_TO_WINDOW |
|
||||
PFD_SUPPORT_OPENGL |
|
||||
PFD_DOUBLEBUFFER |
|
||||
PFD_STEREO_DONTCARE;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = 32;
|
||||
pfd.cRedBits = 8;
|
||||
pfd.cRedShift = 16;
|
||||
pfd.cGreenBits = 8;
|
||||
pfd.cGreenShift = 8;
|
||||
pfd.cBlueBits = 8;
|
||||
pfd.cBlueShift = 0;
|
||||
pfd.cAlphaBits = 0;
|
||||
pfd.cAlphaShift = 0;
|
||||
pfd.cAccumBits = 64;
|
||||
pfd.cAccumRedBits = 16;
|
||||
pfd.cAccumGreenBits = 16;
|
||||
pfd.cAccumBlueBits = 16;
|
||||
pfd.cAccumAlphaBits = 0;
|
||||
pfd.cDepthBits = 32;
|
||||
pfd.cStencilBits = 8;
|
||||
pfd.cAuxBuffers = 0;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
pfd.bReserved = 0;
|
||||
pfd.dwLayerMask = 0;
|
||||
pfd.dwVisibleMask = 0;
|
||||
pfd.dwDamageMask = 0;
|
||||
|
||||
int pixelIndex = ::ChoosePixelFormat(aHdc,&pfd);
|
||||
if (pixelIndex==0) {
|
||||
// Let's choose a default index.
|
||||
pixelIndex = 1;
|
||||
if (::DescribePixelFormat(aHdc,
|
||||
pixelIndex,
|
||||
sizeof(PIXELFORMATDESCRIPTOR),
|
||||
&pfd)==0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (::SetPixelFormat(aHdc,pixelIndex,&pfd)==FALSE) return false;
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
HGLRC fContext;
|
||||
HDC fHDC;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,418 @@
|
||||
// Copyright (C) 2010, Guy Barrand. All rights reserved.
|
||||
// See the file tools.license for terms.
|
||||
|
||||
#ifndef tools_Windows_glarea
|
||||
#define tools_Windows_glarea
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <wingdi.h>
|
||||
|
||||
#include <tools/sg/device_interactor>
|
||||
#include <tools/sg/keys>
|
||||
//#include <tools/log_file>
|
||||
|
||||
#include <string>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#else
|
||||
#define TOOLS_WINDOWS_TOUCH
|
||||
#endif
|
||||
|
||||
namespace tools {
|
||||
namespace Windows {
|
||||
|
||||
#ifdef TOOLS_WINDOWS_TOUCH
|
||||
inline bool is_message_touch_event() {
|
||||
// from https://stackoverflow.com/questions/29857587/detect-if-wm-mousemove-is-caused-by-touch-pen.
|
||||
static const LONG_PTR c_SIGNATURE_MASK = 0xFFFFFF00;
|
||||
static const LONG_PTR c_MOUSEEVENTF_FROMTOUCH = 0xFF515700;
|
||||
LONG_PTR extraInfo = ::GetMessageExtraInfo();
|
||||
return ( ( extraInfo & c_SIGNATURE_MASK ) == c_MOUSEEVENTF_FROMTOUCH );
|
||||
}
|
||||
#endif
|
||||
|
||||
class glarea {
|
||||
static const std::string& s_class() {
|
||||
static const std::string s_v("tools::Windows::glarea");
|
||||
return s_v;
|
||||
}
|
||||
static void register_class(){
|
||||
static bool s_done = false; //not const, then not thread safe.
|
||||
if(!s_done) {
|
||||
WNDCLASS wc;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.lpfnWndProc = (WNDPROC)proc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = ::GetModuleHandle(NULL);
|
||||
wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
|
||||
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
|
||||
wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
|
||||
wc.lpszMenuName = s_class().c_str();
|
||||
wc.lpszClassName = s_class().c_str();
|
||||
::RegisterClass(&wc);
|
||||
s_done = true;
|
||||
}
|
||||
}
|
||||
public:
|
||||
virtual void resize(unsigned int,unsigned int){}
|
||||
virtual void paint(unsigned int a_w,unsigned int a_h) {}
|
||||
virtual void close(){}
|
||||
|
||||
virtual void left_button_up(unsigned int a_x,unsigned int a_y) {}
|
||||
virtual void left_button_down(unsigned int a_x,unsigned int a_y) {}
|
||||
virtual void mouse_move(unsigned int a_x,unsigned int a_y,bool) {}
|
||||
public:
|
||||
glarea(HWND a_parent)
|
||||
:m_parent(a_parent)
|
||||
,m_hwnd(0)
|
||||
,m_context(0)
|
||||
,m_HDC(0)
|
||||
,m_touch_available(false)
|
||||
,m_interactor(0)
|
||||
{
|
||||
register_class();
|
||||
// The WS_BORDER is needed. Else probleme of size at startup.
|
||||
RECT rect;
|
||||
::GetClientRect(m_parent,&rect);
|
||||
//printf("debug : glarea : ca : %d %d\n",rect.right-rect.left,rect.bottom-rect.top);
|
||||
//inlib::log_file::get().writef("debug : glarea : ca : %d %d\n",rect.right-rect.left,rect.bottom-rect.top);
|
||||
m_hwnd = ::CreateWindow(s_class().c_str(),
|
||||
NULL,
|
||||
WS_CHILD | WS_VISIBLE,
|
||||
0,0,
|
||||
rect.right-rect.left,
|
||||
rect.bottom-rect.top,
|
||||
m_parent,NULL,
|
||||
GetWindowInstance(m_parent),
|
||||
NULL);
|
||||
if(!m_hwnd) return;
|
||||
::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this));
|
||||
|
||||
// initialize OpenGL rendering :
|
||||
m_HDC = ::GetDC(m_hwnd);
|
||||
if(m_HDC && SetWindowPixelFormat(m_HDC) ) {
|
||||
m_context = ::wglCreateContext(m_HDC);
|
||||
}
|
||||
|
||||
#ifdef TOOLS_WINDOWS_TOUCH
|
||||
{BYTE digitizer_status = (BYTE)::GetSystemMetrics(SM_DIGITIZER);
|
||||
if((digitizer_status & (0x80 + 0x40)) == 0) {
|
||||
m_touch_available = false;
|
||||
} else {
|
||||
//BYTE nInputs = (BYTE)::GetSystemMetrics(SM_MAXIMUMTOUCHES);
|
||||
m_touch_available = true;
|
||||
if(!::RegisterTouchWindow(m_hwnd,0)) m_touch_available = false;
|
||||
}}
|
||||
#endif
|
||||
|
||||
}
|
||||
virtual ~glarea(){
|
||||
if(::wglGetCurrentContext()!=NULL) ::wglMakeCurrent(NULL,NULL);
|
||||
if(m_context) {
|
||||
::wglDeleteContext(m_context);
|
||||
m_context = 0;
|
||||
}
|
||||
if(m_HDC && m_hwnd) ::ReleaseDC(m_hwnd,m_HDC);
|
||||
if(m_hwnd) {
|
||||
::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(NULL));
|
||||
::DestroyWindow(m_hwnd);
|
||||
m_hwnd = 0;
|
||||
}
|
||||
}
|
||||
protected:
|
||||
glarea(const glarea& a_from)
|
||||
:m_parent(a_from.m_parent)
|
||||
,m_hwnd(0)
|
||||
,m_context(0)
|
||||
,m_HDC(0)
|
||||
,m_touch_available(a_from.m_touch_available)
|
||||
,m_interactor(0)
|
||||
{
|
||||
if(!m_parent) return;
|
||||
register_class();
|
||||
RECT rect;
|
||||
::GetClientRect(m_parent,&rect);
|
||||
m_hwnd = ::CreateWindow(s_class().c_str(),
|
||||
NULL,
|
||||
WS_CHILD | WS_VISIBLE,
|
||||
0,0,
|
||||
rect.right-rect.left,
|
||||
rect.bottom-rect.top,
|
||||
m_parent,NULL,
|
||||
GetWindowInstance(m_parent),
|
||||
NULL);
|
||||
if(!m_hwnd) return;
|
||||
::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this));
|
||||
|
||||
// initialize OpenGL rendering :
|
||||
m_HDC = ::GetDC(m_hwnd);
|
||||
if(m_HDC && SetWindowPixelFormat(m_HDC) ) {
|
||||
m_context = ::wglCreateContext(m_HDC);
|
||||
}
|
||||
|
||||
#ifdef TOOLS_WINDOWS_TOUCH
|
||||
if(a_from.m_touch_available) {
|
||||
if(!::RegisterTouchWindow(m_hwnd,0)) m_touch_available = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
protected:
|
||||
glarea& operator=(const glarea&){return *this;}
|
||||
public:
|
||||
void set_client_area_size(unsigned int a_w,unsigned int a_h) {
|
||||
RECT rect;
|
||||
::GetClientRect(m_hwnd,&rect);
|
||||
::MoveWindow(m_hwnd,rect.left,rect.top,a_w,a_h,TRUE);
|
||||
}
|
||||
HWND hwnd() const {return m_hwnd;}
|
||||
void post_WM_PAINT() const {
|
||||
::PostMessage(m_hwnd,WM_PAINT,(WPARAM)0,(LPARAM)0);
|
||||
}
|
||||
void send_WM_PAINT() const {
|
||||
::SendMessage(m_hwnd,WM_PAINT,(WPARAM)0,(LPARAM)0);
|
||||
}
|
||||
void wm_paint() {
|
||||
PAINTSTRUCT ps;
|
||||
//HDC hDC =
|
||||
BeginPaint(m_hwnd,&ps);
|
||||
if(m_HDC && m_context) {
|
||||
::wglMakeCurrent(m_HDC,m_context);
|
||||
|
||||
RECT rect;
|
||||
::GetClientRect(m_hwnd,&rect);
|
||||
unsigned int w = rect.right-rect.left;
|
||||
unsigned int h = rect.bottom-rect.top;
|
||||
|
||||
//printf("debug : glarea : paint : %d %d\n",w,h);
|
||||
//inlib::log_file::get().writef("debug : glarea : paint : %d %d\n",w,h);
|
||||
|
||||
paint(w,h);
|
||||
|
||||
::SwapBuffers(m_HDC);
|
||||
::wglMakeCurrent(m_HDC,0);
|
||||
}
|
||||
EndPaint(m_hwnd,&ps);
|
||||
}
|
||||
public:
|
||||
void set_device_interactor(tools::sg::device_interactor* a_interactor) {m_interactor = a_interactor;} //we do not have ownership.
|
||||
protected:
|
||||
bool is_touch_event() {
|
||||
#ifdef TOOLS_WINDOWS_TOUCH
|
||||
if(!m_touch_available) return false;
|
||||
return is_message_touch_event();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
protected:
|
||||
static LRESULT CALLBACK proc(HWND a_hwnd,UINT a_msg,WPARAM a_wparam,LPARAM a_lparam) {
|
||||
switch (a_msg) {
|
||||
case WM_SIZE:{
|
||||
int width = LOWORD(a_lparam);
|
||||
int height = HIWORD(a_lparam);
|
||||
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) {
|
||||
_this->resize(width,height);
|
||||
} else {
|
||||
// CreateWindow send a WM_SIZE but GWLP_USERDATA not yet set.
|
||||
}
|
||||
}return 0;
|
||||
case WM_PAINT:{
|
||||
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) _this->wm_paint();
|
||||
}return 0;
|
||||
|
||||
case WM_KEYDOWN:{
|
||||
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) {
|
||||
if(_this->m_interactor) {
|
||||
tools::sg::key_down_event event(_this->convert(a_wparam));
|
||||
_this->m_interactor->key_press(event);
|
||||
}
|
||||
}
|
||||
} return 0;
|
||||
case WM_KEYUP:{
|
||||
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) {
|
||||
if(_this->m_interactor) {
|
||||
tools::sg::key_up_event event(_this->convert(a_wparam));
|
||||
_this->m_interactor->key_release(event);
|
||||
}
|
||||
}
|
||||
} return 0;
|
||||
|
||||
case WM_LBUTTONDOWN:{
|
||||
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) {
|
||||
if(_this->m_interactor) {
|
||||
tools::sg::mouse_down_event event(LOWORD(a_lparam),HIWORD(a_lparam));
|
||||
_this->m_interactor->mouse_press(event);
|
||||
} else {
|
||||
RECT rect;
|
||||
::GetClientRect(a_hwnd,&rect);
|
||||
unsigned int h = rect.bottom-rect.top;
|
||||
if(!_this->is_touch_event()) _this->left_button_down(LOWORD(a_lparam),h-HIWORD(a_lparam));
|
||||
}
|
||||
}
|
||||
}return 0;
|
||||
case WM_LBUTTONUP:{
|
||||
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) {
|
||||
if(_this->m_interactor) {
|
||||
tools::sg::mouse_up_event event(LOWORD(a_lparam),HIWORD(a_lparam));
|
||||
_this->m_interactor->mouse_release(event);
|
||||
} else {
|
||||
RECT rect;
|
||||
::GetClientRect(a_hwnd,&rect);
|
||||
unsigned int h = rect.bottom-rect.top;
|
||||
if(!_this->is_touch_event()) _this->left_button_up(LOWORD(a_lparam),h-HIWORD(a_lparam));
|
||||
}
|
||||
}
|
||||
} return 0;
|
||||
case WM_MOUSEMOVE:{
|
||||
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) {
|
||||
if(_this->m_interactor) {
|
||||
tools::sg::mouse_move_event event(LOWORD(a_lparam),HIWORD(a_lparam),0,0,false);
|
||||
_this->m_interactor->mouse_move(event);
|
||||
} else {
|
||||
WPARAM state = a_wparam;
|
||||
bool ldown = ((state & MK_LBUTTON)==MK_LBUTTON)?true:false;
|
||||
RECT rect;
|
||||
::GetClientRect(a_hwnd,&rect);
|
||||
unsigned int h = rect.bottom-rect.top;
|
||||
if(!_this->is_touch_event()) _this->mouse_move(LOWORD(a_lparam),h-HIWORD(a_lparam),ldown);
|
||||
}
|
||||
}
|
||||
|
||||
}return 0;
|
||||
|
||||
case WM_MOUSEWHEEL:{
|
||||
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) {
|
||||
if(_this->m_interactor) {
|
||||
tools::sg::wheel_rotate_event event(GET_WHEEL_DELTA_WPARAM(a_wparam));
|
||||
_this->m_interactor->wheel_rotate(event);
|
||||
}
|
||||
}
|
||||
} return 0;
|
||||
|
||||
#ifdef TOOLS_WINDOWS_TOUCH
|
||||
case WM_TOUCH:{
|
||||
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this && _this->m_touch_available) {
|
||||
RECT rect;
|
||||
//::GetWindowRect(hwnd,&rect); ???
|
||||
::GetClientRect(a_hwnd,&rect);
|
||||
unsigned int h = rect.bottom-rect.top;
|
||||
|
||||
unsigned int num_inputs = (int)a_wparam;
|
||||
//::printf("debug : WM_TOUCH : 001 : %d\n",num_inputs);
|
||||
TOUCHINPUT* ti = new TOUCHINPUT[num_inputs];
|
||||
POINT p;
|
||||
if(::GetTouchInputInfo((HTOUCHINPUT)a_lparam,num_inputs,ti,sizeof(TOUCHINPUT))) {
|
||||
for(unsigned int i=0;i<num_inputs; ++i) {
|
||||
p.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
|
||||
p.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
|
||||
if(!::ScreenToClient(a_hwnd,&p)) {}
|
||||
if(ti[i].dwFlags & TOUCHEVENTF_DOWN) {
|
||||
//::printf("debug : TOUCHEVENTF_DOWN %lu %lu\n",p.x,p.y);
|
||||
_this->left_button_down(p.x,h-p.y);
|
||||
} else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
|
||||
//::printf("debug : TOUCHEVENTF_UP %lu %lu\n",p.x,p.y);
|
||||
_this->left_button_up(p.x,h-p.y);
|
||||
} else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
|
||||
bool ldown = true; //we assume that a TOUCHEVENT_DOWN had been done.
|
||||
//::printf("debug : TOUCHEVENTF_MOVE %lu %lu\n",p.x,p.y);
|
||||
_this->mouse_move(p.x,h-p.y,ldown);
|
||||
}
|
||||
}
|
||||
}
|
||||
::CloseTouchInputHandle((HTOUCHINPUT)a_lparam);
|
||||
delete [] ti;
|
||||
}
|
||||
}return 0;
|
||||
#endif //TOOLS_WINDOWS_TOUCH
|
||||
case WM_DESTROY:wm__destroy(a_hwnd);return 0;
|
||||
}
|
||||
return (DefWindowProc(a_hwnd,a_msg,a_wparam,a_lparam));
|
||||
}
|
||||
static bool SetWindowPixelFormat(HDC a_HDC){
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags =
|
||||
PFD_DRAW_TO_WINDOW |
|
||||
PFD_SUPPORT_OPENGL |
|
||||
PFD_DOUBLEBUFFER |
|
||||
PFD_STEREO_DONTCARE;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = 32;
|
||||
pfd.cRedBits = 8;
|
||||
pfd.cRedShift = 16;
|
||||
pfd.cGreenBits = 8;
|
||||
pfd.cGreenShift = 8;
|
||||
pfd.cBlueBits = 8;
|
||||
pfd.cBlueShift = 0;
|
||||
pfd.cAlphaBits = 0;
|
||||
pfd.cAlphaShift = 0;
|
||||
pfd.cAccumBits = 64;
|
||||
pfd.cAccumRedBits = 16;
|
||||
pfd.cAccumGreenBits = 16;
|
||||
pfd.cAccumBlueBits = 16;
|
||||
pfd.cAccumAlphaBits = 0;
|
||||
pfd.cDepthBits = 32;
|
||||
pfd.cStencilBits = 8;
|
||||
pfd.cAuxBuffers = 0;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
pfd.bReserved = 0;
|
||||
pfd.dwLayerMask = 0;
|
||||
pfd.dwVisibleMask = 0;
|
||||
pfd.dwDamageMask = 0;
|
||||
|
||||
int pixelIndex = ::ChoosePixelFormat(a_HDC,&pfd);
|
||||
if (pixelIndex==0) {
|
||||
// Let's choose a default index.
|
||||
pixelIndex = 1;
|
||||
if (::DescribePixelFormat(a_HDC,
|
||||
pixelIndex,
|
||||
sizeof(PIXELFORMATDESCRIPTOR),
|
||||
&pfd)==0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (::SetPixelFormat(a_HDC,pixelIndex,&pfd)==FALSE) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
static void wm__destroy(HWND a_hwnd) {
|
||||
glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) { //How to be sure that we have a glarea* ???
|
||||
_this->close();
|
||||
if(_this->m_hwnd!=a_hwnd) {
|
||||
//::printf("WinTk::Component::wm_destroy : HWND mismatch !\n");
|
||||
}
|
||||
_this->m_hwnd = 0;
|
||||
}
|
||||
::SetWindowLongPtr(a_hwnd,GWLP_USERDATA,LONG_PTR(NULL));
|
||||
}
|
||||
protected:
|
||||
tools::key_code convert(WPARAM a_key) {
|
||||
if(a_key==VK_SHIFT) return tools::sg::key_shift();
|
||||
return (tools::key_code)a_key;
|
||||
}
|
||||
protected:
|
||||
HWND m_parent;
|
||||
HWND m_hwnd;
|
||||
HGLRC m_context;
|
||||
HDC m_HDC;
|
||||
bool m_touch_available;
|
||||
tools::sg::device_interactor* m_interactor;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright (C) 2010, Guy Barrand. All rights reserved.
|
||||
// See the file tools.license for terms.
|
||||
|
||||
#ifndef tools_Windows_session
|
||||
#define tools_Windows_session
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace tools {
|
||||
namespace Windows {
|
||||
|
||||
class session {
|
||||
public:
|
||||
session(std::ostream& a_out):m_out(a_out){}
|
||||
virtual ~session() {}
|
||||
protected:
|
||||
session(const session& a_from):m_out(a_from.m_out){}
|
||||
session& operator=(const session&){return *this;}
|
||||
public:
|
||||
std::ostream& out() const {return m_out;}
|
||||
|
||||
bool is_valid() const {return true;}
|
||||
|
||||
bool steer() {
|
||||
while(true) {
|
||||
MSG event;
|
||||
BOOL status = ::GetMessage(&event,NULL,0,0);
|
||||
if(status == -1) { // This may happen (dixit Microsoft doc).
|
||||
break;
|
||||
} else if(status == 0) { //WM_QUIT
|
||||
break;
|
||||
} else {
|
||||
::TranslateMessage(&event);
|
||||
::DispatchMessage (&event);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sync() {
|
||||
MSG event;
|
||||
while(::PeekMessage(&event,NULL,0,0,PM_REMOVE)) {
|
||||
if(event.message==WM_QUIT) return false;
|
||||
::TranslateMessage(&event);
|
||||
::DispatchMessage(&event);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void show_window(HWND a_hwnd){
|
||||
::SetForegroundWindow(a_hwnd);
|
||||
::ShowWindow(a_hwnd,SW_SHOWDEFAULT);
|
||||
::UpdateWindow(a_hwnd);
|
||||
::DrawMenuBar(a_hwnd);
|
||||
}
|
||||
|
||||
void set_size(HWND a_hwnd,unsigned int a_width,unsigned int a_height) {
|
||||
::MoveWindow(a_hwnd,0,0,a_width,a_height,TRUE);
|
||||
}
|
||||
|
||||
//void post(HWND a_hwnd,LPARAM a_msg){
|
||||
// ::PostMessage(a_hwnd,WM_USER,(WPARAM)0,a_msg);
|
||||
//}
|
||||
protected:
|
||||
std::ostream& m_out;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,90 @@
|
||||
// Copyright (C) 2010, Guy Barrand. All rights reserved.
|
||||
// See the file tools.license for terms.
|
||||
|
||||
#ifndef tools_Windows_sg_viewer
|
||||
#define tools_Windows_sg_viewer
|
||||
|
||||
#include "session"
|
||||
#include "window"
|
||||
#include "glarea"
|
||||
|
||||
#include "../sg/GL_viewer"
|
||||
|
||||
// disable the warning about the usage of "this" in the constructor.
|
||||
#pragma warning(disable:4355)
|
||||
|
||||
namespace tools {
|
||||
namespace Windows {
|
||||
|
||||
class sg_viewer : public window, public sg::GL_viewer {
|
||||
typedef window parent_window;
|
||||
typedef sg::GL_viewer parent_viewer;
|
||||
public:
|
||||
virtual void close() {}
|
||||
public:
|
||||
sg_viewer(session& a_session,
|
||||
int a_x = 0,int a_y = 0,
|
||||
unsigned int a_width = 500,unsigned int a_height = 500,
|
||||
const std::string& a_title = "")
|
||||
:parent_window(a_title.c_str(),a_x,a_y,a_width,a_height)
|
||||
,parent_viewer(a_session.out(),a_width,a_height)
|
||||
,m_session(a_session)
|
||||
,m_glarea(m_hwnd,*this)
|
||||
{
|
||||
parent_window::set_focus_hwnd(m_glarea.hwnd());
|
||||
}
|
||||
virtual ~sg_viewer() {}
|
||||
protected:
|
||||
sg_viewer(const sg_viewer& a_from)
|
||||
:parent_window(a_from)
|
||||
,parent_viewer(a_from)
|
||||
,m_session(a_from.m_session)
|
||||
,m_glarea(a_from.m_glarea)
|
||||
{}
|
||||
sg_viewer& operator=(const sg_viewer& a_from){
|
||||
parent_window::operator=(a_from);
|
||||
return *this;
|
||||
}
|
||||
public:
|
||||
bool has_window() const {return m_hwnd?true:false;} //for SWIG
|
||||
|
||||
HWND window() const {return m_hwnd;}
|
||||
|
||||
bool show() {
|
||||
if(!m_hwnd) return false;
|
||||
m_session.show_window(m_hwnd);
|
||||
return true;
|
||||
}
|
||||
|
||||
void win_render() {m_glarea.wm_paint();}
|
||||
|
||||
|
||||
public:
|
||||
void set_device_interactor(tools::sg::device_interactor* a_interactor) { //we do not have ownership.
|
||||
m_glarea.set_device_interactor(a_interactor);
|
||||
}
|
||||
protected:
|
||||
class _glarea : public glarea {
|
||||
public:
|
||||
virtual void paint(unsigned int a_w,unsigned int a_h) {
|
||||
m_viewer.set_size(a_w,a_h);
|
||||
m_viewer.render();
|
||||
}
|
||||
public:
|
||||
_glarea(HWND a_parent,parent_viewer& a_viewer)
|
||||
:glarea(a_parent)
|
||||
,m_viewer(a_viewer)
|
||||
{}
|
||||
protected:
|
||||
parent_viewer& m_viewer;
|
||||
};
|
||||
|
||||
protected:
|
||||
session& m_session;
|
||||
_glarea m_glarea;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,601 @@
|
||||
// Copyright (C) 2010, Guy Barrand. All rights reserved.
|
||||
// See the file tools.license for terms.
|
||||
|
||||
#ifndef tools_Windows_tools
|
||||
#define tools_Windows_tools
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace tools {
|
||||
namespace WinTk {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool GetClassName(HWND aWindow,std::string& a_value) {
|
||||
if(!aWindow) {a_value.clear();return false;}
|
||||
char className[256];
|
||||
::GetClassName(aWindow,className,128);
|
||||
a_value = std::string(className);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline HWND GetChildByClassName(HWND aWindow,const std::string& aClassName) {
|
||||
// A CBS_SIMPLE has two children of class ComboLBox and Edit.
|
||||
// At creation, a CBS_DROPDOWN has one child of class Edit.
|
||||
if(!aWindow) return NULL;
|
||||
HWND child = GetFirstChild(aWindow);
|
||||
std::string ss;
|
||||
while(child) {
|
||||
GetClassName(child,ss);
|
||||
if(ss==aClassName) return child;
|
||||
child = GetNextSibling(child);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline void SetGeometry(HWND aWindow,int aX,int aY,unsigned int aWidth,unsigned int aHeight) {
|
||||
if(!aWindow) return;
|
||||
std::string className;
|
||||
GetClassName(aWindow,className);
|
||||
if(className=="ComboBox") {
|
||||
// For a Combo the height is the visible part + the height of the list !
|
||||
// (A combo may have no edit control).
|
||||
::MoveWindow(aWindow,aX,aY,aWidth,200,TRUE);
|
||||
} else {
|
||||
::MoveWindow(aWindow,aX,aY,aWidth,aHeight,TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
inline void GetSize(HWND aWindow,int& aWidth,int& aHeight) {
|
||||
RECT rect;
|
||||
::GetWindowRect(aWindow,&rect);
|
||||
aWidth = rect.right-rect.left;
|
||||
aHeight = rect.bottom-rect.top;
|
||||
}
|
||||
|
||||
inline unsigned int GetNumberOfChildren(HWND aWindow) {
|
||||
unsigned int number = 0;
|
||||
HWND child = GetFirstChild(aWindow);
|
||||
while(child) {
|
||||
number++;
|
||||
child = GetNextSibling(child);
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
inline HWND GetLastChild(HWND aWindow) {
|
||||
HWND child = GetFirstChild(aWindow);
|
||||
while(child) {
|
||||
HWND next = GetNextSibling(child);
|
||||
if(!next) return child;
|
||||
child = next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void GetText(HWND aWindow,std::string& a_value) {
|
||||
int l = ::GetWindowTextLength(aWindow);
|
||||
a_value.resize(l);
|
||||
::GetWindowText(aWindow,(char*)a_value.c_str(),l+1);
|
||||
}
|
||||
|
||||
/*
|
||||
inline void PrintChildren(HWND aWindow) {
|
||||
// A CBS_SIMPLE has two children of class ComboLBox and Edit.
|
||||
// At creation, a CBS_DROPDOWN has one child of class Edit.
|
||||
if(!aWindow) return;
|
||||
HWND child = GetFirstChild(aWindow);
|
||||
while(child) {
|
||||
//printf("debug : window : %ld, child : %ld class \"%s\"\n",
|
||||
// aWindow,child,ClassName(child).c_str());
|
||||
child = GetNextSibling(child);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool IsStyle(HWND aWindow,LONG aStyle) {
|
||||
LONG_PTR style = ::GetWindowLongPtr(aWindow,GWL_STYLE);
|
||||
return ( ((style & aStyle ) == aStyle) ? true : false);
|
||||
}
|
||||
|
||||
inline void ChangeStyle(HWND aWindow,LONG aStyle,bool aValue) {
|
||||
LONG_PTR style = ::GetWindowLongPtr(aWindow,GWL_STYLE);
|
||||
if(aValue) { //Enable style.
|
||||
style = style | aStyle;
|
||||
} else { //Disbale style.
|
||||
style = style & ~aStyle;
|
||||
}
|
||||
::SetWindowLongPtr(aWindow,GWL_STYLE,style);
|
||||
}
|
||||
|
||||
inline bool IsShell(HWND aWindow) {
|
||||
if(IsStyle(aWindow,WS_OVERLAPPEDWINDOW)) return true;
|
||||
if(IsStyle(aWindow,WS_POPUP)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
inline HWND GetShell(HWND aWindow) {
|
||||
HWND window = aWindow;
|
||||
if(IsShell(window)) return window;
|
||||
while(true) {
|
||||
HWND parent = GetParent(window);
|
||||
if(!parent) return window;
|
||||
if(IsShell(parent)) return parent;
|
||||
window = parent;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline bool Show(HWND aWindow) {
|
||||
HWND shell = GetShell(aWindow);
|
||||
if(!shell) return false;
|
||||
::SetForegroundWindow(shell);
|
||||
::ShowWindow(shell,SW_SHOWDEFAULT);
|
||||
::UpdateWindow(shell);
|
||||
::DrawMenuBar(shell);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Hide(HWND aWindow) {
|
||||
HWND shell = GetShell(aWindow);
|
||||
if(!shell) return false;
|
||||
::ShowWindow(shell,SW_HIDE);
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool IsTabStop(HWND aWindow) {
|
||||
LONG_PTR style = ::GetWindowLongPtr(aWindow,GWL_STYLE);
|
||||
return ((style & WS_TABSTOP ) == WS_TABSTOP ? true : false);
|
||||
}
|
||||
|
||||
inline HWND GetTabStopInTree(HWND aWindow,bool aForward) {
|
||||
if(IsTabStop(aWindow)) return aWindow;
|
||||
HWND child = aForward ? GetFirstChild(aWindow) : GetLastChild(aWindow);
|
||||
while(child) {
|
||||
HWND tabStop = GetTabStopInTree(child,aForward);
|
||||
if(tabStop) return tabStop;
|
||||
child = aForward ? GetNextSibling(child) : GetPrevSibling(child);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline HWND GetTabStopInSibling(HWND aWindow,bool aForward) {
|
||||
if(!aWindow) return NULL;
|
||||
HWND child = aForward ? GetNextSibling(aWindow) : GetPrevSibling(aWindow);
|
||||
while(child) {
|
||||
HWND tabStop = GetTabStopInTree(child,aForward);
|
||||
if(tabStop) return tabStop;
|
||||
child = aForward ? GetNextSibling(child) : GetPrevSibling(child);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline HWND GetTabStop(HWND aDialog,HWND aWindow,bool aForward = true) {
|
||||
if(!aWindow) return NULL;
|
||||
HWND window = aWindow;
|
||||
while(window && (window!=aDialog) ) {
|
||||
HWND tabStop = GetTabStopInSibling(window,aForward);
|
||||
if(tabStop) return tabStop;
|
||||
window = GetParent(window);
|
||||
}
|
||||
return GetTabStopInTree(aDialog,aForward);
|
||||
}
|
||||
|
||||
inline HBITMAP CreateDIB(HDC aDC,int aWidth,int aHeight,int aBPP /*16||24||32*/,void** aBits) {
|
||||
if((aBPP!=24) && (aBPP!=32)) return 0;
|
||||
|
||||
BITMAPINFO format;
|
||||
BITMAPINFOHEADER* header = (BITMAPINFOHEADER*)&format;
|
||||
header->biSize = sizeof(BITMAPINFOHEADER);
|
||||
header->biWidth = aWidth;
|
||||
header->biHeight = -aHeight;
|
||||
header->biPlanes = 1;
|
||||
header->biBitCount = aBPP;
|
||||
header->biCompression = BI_RGB;
|
||||
header->biSizeImage = 0;
|
||||
header->biXPelsPerMeter = 0;
|
||||
header->biYPelsPerMeter = 0;
|
||||
header->biClrUsed = 0;
|
||||
header->biClrImportant = 0;
|
||||
|
||||
UINT flag = DIB_RGB_COLORS;
|
||||
HBITMAP bitmap = ::CreateDIBSection(aDC,&format,flag,(void**)aBits,NULL,0);
|
||||
|
||||
if(!(*aBits)) return 0;
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#include <commctrl.h>
|
||||
|
||||
namespace tools {
|
||||
namespace WinTk {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
inline bool TreeGetItemLabel(HWND aWindow,HTREEITEM aItem,std::string& a_value) {
|
||||
TCHAR text[256];
|
||||
TV_ITEM item;
|
||||
item.hItem = aItem;
|
||||
item.mask = TVIF_TEXT;
|
||||
item.pszText = text;
|
||||
item.cchTextMax = 256;
|
||||
if(!TreeView_GetItem(aWindow,&item)) {a_value.clear();return false;}
|
||||
a_value = std::string(text);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool TreeIsItemBranch(HWND aWindow,HTREEITEM aItem) {
|
||||
TV_ITEM item;
|
||||
item.hItem = aItem;
|
||||
item.mask = TVIF_CHILDREN;
|
||||
if(!TreeView_GetItem(aWindow,&item)) return 0;
|
||||
return item.cChildren?true:false;
|
||||
}
|
||||
|
||||
inline bool TreeIsItemExpanded(HWND aWindow,HTREEITEM aItem) {
|
||||
TV_ITEM item;
|
||||
item.hItem = aItem;
|
||||
item.mask = TVIS_EXPANDED;
|
||||
if(!TreeView_GetItem(aWindow,&item)) return 0;
|
||||
return ((item.state & TVIS_EXPANDED)== TVIS_EXPANDED) ? true : false;
|
||||
}
|
||||
|
||||
inline void TreeGetItemPath(HWND aWindow,HTREEITEM aItem,std::string& a_value) {
|
||||
HTREEITEM item = aItem;
|
||||
a_value.clear();
|
||||
std::string ss;
|
||||
while(item && (item!=TVI_ROOT)) {
|
||||
TreeGetItemLabel(aWindow,item,ss);
|
||||
std::string opath = a_value;
|
||||
a_value = "\n";
|
||||
a_value += ss;
|
||||
a_value += opath;
|
||||
item = TreeView_GetParent(aWindow,item);
|
||||
}
|
||||
// Remove the leading \n
|
||||
if(a_value.size()) a_value = a_value.substr(1,a_value.size()-1);
|
||||
}
|
||||
|
||||
inline void TreeGetItemXML(HWND aWindow,HTREEITEM aItem,std::string& a_value) {
|
||||
//return a XML string representing this tree
|
||||
std::string spaceItem = "";
|
||||
std::string spaceRoot = "";
|
||||
std::string ss;
|
||||
a_value.clear();
|
||||
do {
|
||||
a_value += spaceRoot + "<treeItem>";
|
||||
a_value += spaceItem + "<label>";
|
||||
TreeGetItemLabel(aWindow,aItem,ss);
|
||||
a_value.append(ss);
|
||||
a_value += "</label>";
|
||||
a_value += spaceItem + "<opened>";
|
||||
if (TreeIsItemExpanded(aWindow,aItem)) a_value.append("true");
|
||||
else a_value.append("false");
|
||||
a_value += "</opened>";
|
||||
if (TreeView_GetChild(aWindow,aItem)) {
|
||||
TreeGetItemXML(aWindow,TreeView_GetChild(aWindow,aItem),ss);
|
||||
a_value += ss;
|
||||
}
|
||||
a_value += spaceRoot + "</treeItem>";
|
||||
aItem = TreeView_GetNextSibling(aWindow,aItem);
|
||||
}
|
||||
while (aItem);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
inline int smanip_axtoi(const std::string& a_string) {
|
||||
// convert from ASCII hex to int
|
||||
// Exa : "FF" -> 256.
|
||||
int x = 0;
|
||||
size_t n = a_string.size();
|
||||
// convert n nibbles
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char c = a_string[i];
|
||||
// numbers 0 - 9
|
||||
if ((c > 0x2F) && (c < 0x3A))
|
||||
x += ((c - 0x30) << ((n - i - 1) * 4));
|
||||
|
||||
// capital letters A - F
|
||||
if ((c > 0x40) && (c < 0x47))
|
||||
x += ((c - 0x41 + 0x0A) << ((n - i - 1) * 4));
|
||||
|
||||
// lower case letters a - f
|
||||
if ((c > 0x60) && (c < 0x67))
|
||||
x += ((c - 0x61 + 0x0A) << ((n - i - 1) * 4));
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#include <tools/svalues>
|
||||
|
||||
namespace tools {
|
||||
namespace WinTk {
|
||||
|
||||
inline HBITMAP ConvertXpmToDIB(HDC aDC,const std::vector<std::string>& aXPM,int& aWidth,int& aHeight) {
|
||||
// Convert from xpm to DIB (demands hex colors).
|
||||
// From CoinWin/widgets/SoWinBitmapButton.cpp.
|
||||
aWidth = 0;
|
||||
aHeight = 0;
|
||||
if(!aXPM.size()) return 0;
|
||||
|
||||
std::vector<int> vals;
|
||||
tools::values<int>(aXPM[0]," ",false,vals);
|
||||
if(vals.size()!=4) return 0;
|
||||
int width = vals[0];
|
||||
int height = vals[1];
|
||||
int numcol = vals[2];
|
||||
int numchars = vals[3];
|
||||
if(width<=0) return 0;
|
||||
if(height<=0) return 0;
|
||||
if(numcol<=0) return 0;
|
||||
if(numchars<=0) return 0;
|
||||
|
||||
// Check consistency :
|
||||
if((height+numcol)!=aXPM.size()-1) return 0;
|
||||
|
||||
size_t lcolor = 0;
|
||||
int i;
|
||||
for (i = 0; i < numcol; i++) {
|
||||
std::string::size_type pos = aXPM[i+1].rfind("c #");
|
||||
if(pos==std::string::npos) continue; // May be "c None"
|
||||
lcolor = aXPM[i+1].size()-(pos+3);
|
||||
break;
|
||||
}
|
||||
//printf("debug : xpm : numcol %d (%d)\n",numcol,lcolor);
|
||||
|
||||
if( (lcolor!=6) && (lcolor!=12) ) return 0;
|
||||
|
||||
// create color lookup table
|
||||
char* charlookuptable = new char[numcol * numchars];
|
||||
//long* colorlookuptable = new long[numcol];
|
||||
int* rlookuptable = new int[numcol];
|
||||
int* glookuptable = new int[numcol];
|
||||
int* blookuptable = new int[numcol];
|
||||
|
||||
bool done = true;
|
||||
// get colors
|
||||
for (i = 0; i < numcol; i++) {
|
||||
|
||||
const std::string& line = aXPM[i+1];
|
||||
|
||||
// Check consistency :
|
||||
if((int)line.size()<numchars) {
|
||||
done = false;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int j = 0; j < numchars; j ++) {
|
||||
charlookuptable[(i * numchars) + j] = line[j];
|
||||
}
|
||||
|
||||
// Find color by value :
|
||||
std::string::size_type pos = line.find("c #",numchars);
|
||||
if(pos!=std::string::npos) {
|
||||
size_t lc = line.size()-(pos+3);
|
||||
if(lc!=lcolor) {
|
||||
done = false;
|
||||
//printf("debug : xpm : error in \"%s\" %d %d\n",
|
||||
//line.c_str(),lc,lcolor);
|
||||
break;
|
||||
}
|
||||
if(lcolor==6) {
|
||||
rlookuptable[i] = smanip_axtoi(line.substr(pos+3+0,2));
|
||||
glookuptable[i] = smanip_axtoi(line.substr(pos+3+2,2));
|
||||
blookuptable[i] = smanip_axtoi(line.substr(pos+3+4,2));
|
||||
} else { //lcolor 12
|
||||
rlookuptable[i] = smanip_axtoi(line.substr(pos+3+0,2));
|
||||
glookuptable[i] = smanip_axtoi(line.substr(pos+3+4,2));
|
||||
blookuptable[i] = smanip_axtoi(line.substr(pos+3+8,2));
|
||||
}
|
||||
|
||||
//printf("debug : xpm : color %d : (%x,%x,%x)\n",
|
||||
// i,rlookuptable[i],glookuptable[i],blookuptable[i]);
|
||||
|
||||
} else { // Could be "c None"
|
||||
rlookuptable[i] = -1;
|
||||
glookuptable[i] = -1;
|
||||
blookuptable[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
//printf("debug : xpm : read color %d\n",done);
|
||||
|
||||
//WARNING : pixelsize 3 does not work with button in a toolbar.
|
||||
// unsigned char pixelsize = 3;
|
||||
unsigned char pixelsize = 4;
|
||||
|
||||
if(!done) pixelsize = 0; // Will induce a clean exit.
|
||||
|
||||
// create bitmap
|
||||
void* dest;
|
||||
HBITMAP hbmp = CreateDIB(aDC,width,height,pixelsize * 8,&dest);
|
||||
|
||||
if(hbmp) {
|
||||
int noneColor = ::GetSysColor(COLOR_3DFACE);
|
||||
done = true;
|
||||
// put pixels
|
||||
for (i = 0; i < height; i++) {
|
||||
|
||||
const std::string& line = aXPM[i + 1 + numcol];
|
||||
|
||||
// Check consistency :
|
||||
if((int)line.size()!=(numchars*width)) {
|
||||
done = false;
|
||||
break;
|
||||
}
|
||||
|
||||
int y = i * width * pixelsize;
|
||||
|
||||
for (int j = 0; j < width; j++) {
|
||||
|
||||
int x = j * pixelsize;
|
||||
|
||||
// for every color
|
||||
for (int k = 0; k < numcol; k++) {
|
||||
|
||||
bool found = true;
|
||||
for (int l = 0; l < numchars; l++) {
|
||||
if (charlookuptable[(k * numchars) + l]
|
||||
!= line[(j * numchars) + l]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(found) {
|
||||
|
||||
unsigned char r,g,b;
|
||||
if (rlookuptable[k] == -1) {
|
||||
r = (noneColor & 0x00FF0000)>>16;
|
||||
g = (noneColor & 0x0000FF00)>>8;
|
||||
b = noneColor & 0x000000FF;
|
||||
} else {
|
||||
r = rlookuptable[k];
|
||||
g = glookuptable[k];
|
||||
b = blookuptable[k];
|
||||
}
|
||||
|
||||
if(pixelsize==4) {
|
||||
((unsigned char*)dest)[y + x + 0] = b;
|
||||
((unsigned char*)dest)[y + x + 1] = g;
|
||||
((unsigned char*)dest)[y + x + 2] = r;
|
||||
((unsigned char*)dest)[y + x + 3] = 0;
|
||||
} else {
|
||||
((unsigned char*)dest)[y + x + 0] = b;
|
||||
((unsigned char*)dest)[y + x + 1] = g;
|
||||
((unsigned char*)dest)[y + x + 2] = r;
|
||||
}
|
||||
|
||||
// next pixel
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if(!done) {
|
||||
//printf("debug : xpm : can'tread pixels.\n");
|
||||
::DeleteObject(hbmp);
|
||||
hbmp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup
|
||||
delete [] charlookuptable;
|
||||
delete [] rlookuptable;
|
||||
delete [] glookuptable;
|
||||
delete [] blookuptable;
|
||||
|
||||
if(hbmp) {
|
||||
aWidth = width;
|
||||
aHeight = height;
|
||||
}
|
||||
|
||||
return hbmp;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#include <tools/file>
|
||||
|
||||
namespace tools {
|
||||
namespace WinTk {
|
||||
|
||||
inline HBITMAP Read_Xpm(HDC aDC,const std::string& aFileName,int& aWidth,int& aHeight) {
|
||||
aWidth = 0;
|
||||
aHeight = 0;
|
||||
std::vector<std::string> text;
|
||||
//std::string name;
|
||||
//tools::file_name(aFileName,name);
|
||||
if(!tools::file::read(aFileName,text)) return 0;
|
||||
|
||||
std::vector<std::string> xpm;
|
||||
|
||||
{for(size_t index=0;index<text.size();index++) {
|
||||
if(text[index][0]!='"') continue;
|
||||
std::string::size_type l = text[index].size();
|
||||
std::string line = text[index].substr(1,l-1);
|
||||
std::string::size_type pos = line.find("\"");
|
||||
if(pos==std::string::npos) return 0;
|
||||
xpm.push_back(line.substr(0,pos));
|
||||
}}
|
||||
|
||||
if(!xpm.size()) return 0;
|
||||
|
||||
return ConvertXpmToDIB(aDC,xpm,aWidth,aHeight);
|
||||
}
|
||||
|
||||
inline std::string TreeGetItemLabel(HWND aWindow,HTREEITEM aItem) {
|
||||
std::string ss;
|
||||
TreeGetItemLabel(aWindow,aItem,ss);
|
||||
return ss;
|
||||
}
|
||||
|
||||
inline std::string TreeGetItemPath(HWND aWindow,HTREEITEM aItem) {
|
||||
std::string ss;
|
||||
TreeGetItemPath(aWindow,aItem,ss);
|
||||
return ss;
|
||||
}
|
||||
|
||||
inline std::string TreeGetItemXML(HWND aWindow,HTREEITEM aItem) {
|
||||
std::string ss;
|
||||
TreeGetItemXML(aWindow,aItem,ss);
|
||||
return ss;
|
||||
}
|
||||
|
||||
inline std::string GetText(HWND aWindow) {
|
||||
std::string ss;
|
||||
GetText(aWindow,ss);
|
||||
return ss;
|
||||
}
|
||||
|
||||
inline std::string GetClassName(HWND aWindow) {
|
||||
std::string ss;
|
||||
GetClassName(aWindow,ss);
|
||||
return ss;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#include <tools/file_name>
|
||||
|
||||
namespace tools {
|
||||
namespace WinTk {
|
||||
|
||||
inline HBITMAP ReadXpm(HDC aDC,const std::string& aFileName,int& aWidth,int& aHeight) {
|
||||
std::string name;
|
||||
tools::file_name(aFileName,name);
|
||||
return Read_Xpm(aDC,name,aWidth,aHeight);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
// Copyright (C) 2010, Guy Barrand. All rights reserved.
|
||||
// See the file tools.license for terms.
|
||||
|
||||
#ifndef tools_Windows_window
|
||||
#define tools_Windows_window
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <string>
|
||||
|
||||
namespace tools {
|
||||
namespace Windows {
|
||||
|
||||
class window {
|
||||
static const std::string& s_class() {
|
||||
static const std::string s_v("tools::Windows::window");
|
||||
return s_v;
|
||||
}
|
||||
static void register_class(){
|
||||
static bool s_done = false; //not const, then not thread safe.
|
||||
if(!s_done) {
|
||||
WNDCLASS wc;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.lpfnWndProc = (WNDPROC)proc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = ::GetModuleHandle(NULL);
|
||||
wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
|
||||
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
|
||||
wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
|
||||
wc.lpszMenuName = s_class().c_str();
|
||||
wc.lpszClassName = s_class().c_str();
|
||||
::RegisterClass(&wc);
|
||||
s_done = true;
|
||||
}
|
||||
}
|
||||
public:
|
||||
virtual void key_up(){}
|
||||
virtual void key_down(){}
|
||||
virtual void key_left(){}
|
||||
virtual void key_right(){}
|
||||
virtual void key_escape(){}
|
||||
virtual void close(){
|
||||
//if(m_hwnd) ::PostMessage(m_hwnd,WM_QUIT,0,0);
|
||||
::PostQuitMessage(0);
|
||||
}
|
||||
public:
|
||||
window(const char* a_title,int a_x,int a_y,unsigned int a_w,unsigned int a_h,unsigned int a_mask = WS_OVERLAPPEDWINDOW)
|
||||
:m_hwnd(0)
|
||||
,m_key_shift(false)
|
||||
,m_key_ctrl(false)
|
||||
,m_focus_hwnd(0)
|
||||
{
|
||||
// WARNING : given a_w,a_h may not be the client area because of various decorations.
|
||||
// See set_client_area_size() method to enforce a client area size.
|
||||
register_class();
|
||||
m_hwnd = ::CreateWindow(s_class().c_str(),
|
||||
NULL,
|
||||
a_mask,
|
||||
a_x,a_y,
|
||||
a_w,a_h,
|
||||
NULL,NULL,
|
||||
::GetModuleHandle(NULL),
|
||||
NULL);
|
||||
if(!m_hwnd) return;
|
||||
::SetWindowText(m_hwnd,a_title);
|
||||
::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this));
|
||||
}
|
||||
virtual ~window(){
|
||||
if(m_hwnd) {
|
||||
::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(NULL));
|
||||
::DestroyWindow(m_hwnd);
|
||||
m_hwnd = 0;
|
||||
}
|
||||
}
|
||||
protected:
|
||||
window(const window& a_from)
|
||||
:m_hwnd(0)
|
||||
,m_key_shift(a_from.m_key_shift)
|
||||
,m_key_ctrl(a_from.m_key_ctrl)
|
||||
,m_focus_hwnd(0)
|
||||
{
|
||||
/*
|
||||
if(!a_from.m_hwnd) return;
|
||||
int w,h;
|
||||
get_size(a_from.m_hwnd,w,h);
|
||||
register_class();
|
||||
m_hwnd = ::CreateWindow(s_class().c_str(),
|
||||
NULL,
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT,CW_USEDEFAULT,
|
||||
w,h,
|
||||
NULL,NULL,
|
||||
::GetModuleHandle(NULL),
|
||||
NULL);
|
||||
if(!m_hwnd) return;
|
||||
::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this));
|
||||
*/
|
||||
}
|
||||
window& operator=(const window& a_from){
|
||||
m_key_shift = a_from.m_key_shift;
|
||||
m_key_ctrl = a_from.m_key_ctrl;
|
||||
return *this;
|
||||
}
|
||||
public:
|
||||
const window& get_me() const {return *this;}
|
||||
window& get_me() {return *this;}
|
||||
bool key_shift() const {return m_key_shift;}
|
||||
HWND hwnd() const {return m_hwnd;}
|
||||
|
||||
void set_client_area_size(unsigned int a_w,unsigned int a_h) {
|
||||
if(!m_hwnd) return;
|
||||
RECT wrect;
|
||||
::GetWindowRect(m_hwnd,&wrect);
|
||||
unsigned int ww = wrect.right-wrect.left;
|
||||
unsigned int wh = wrect.bottom-wrect.top;
|
||||
|
||||
RECT carect;
|
||||
::GetClientRect(m_hwnd,&carect);
|
||||
unsigned int cw = carect.right-carect.left;
|
||||
unsigned int ch = carect.bottom-carect.top;
|
||||
|
||||
unsigned int woffset = ww-cw;
|
||||
unsigned int hoffset = wh-ch;
|
||||
|
||||
::MoveWindow(m_hwnd,wrect.left,wrect.top,a_w+woffset,a_h+hoffset,TRUE);
|
||||
}
|
||||
void move(unsigned int a_x,unsigned int a_y) {
|
||||
if(!m_hwnd) return;
|
||||
RECT rect;
|
||||
::GetWindowRect(m_hwnd,&rect);
|
||||
unsigned int w = rect.right-rect.left;
|
||||
unsigned int h = rect.bottom-rect.top;
|
||||
::MoveWindow(m_hwnd,a_x,a_y,w,h,TRUE);
|
||||
}
|
||||
|
||||
void set_focus_hwnd(HWND a_hwnd) {m_focus_hwnd = a_hwnd;}
|
||||
HWND focus_hwnd() const {return m_focus_hwnd;}
|
||||
protected:
|
||||
static LRESULT CALLBACK proc(HWND a_hwnd,UINT a_msg,WPARAM a_wparam,LPARAM a_lparam) {
|
||||
switch (a_msg) {
|
||||
// Else :
|
||||
case WM_SIZE:{ // Assume one child window ! FIXME : have a message if not.
|
||||
int width = LOWORD(a_lparam);
|
||||
int height = HIWORD(a_lparam);
|
||||
HWND hwnd = GetFirstChild(a_hwnd);
|
||||
if(hwnd) {
|
||||
::MoveWindow(hwnd,0,0,width,height,TRUE);
|
||||
}
|
||||
}return 0;
|
||||
|
||||
case WM_SETFOCUS:{
|
||||
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) {
|
||||
HWND hwnd = _this->focus_hwnd();
|
||||
if(hwnd) ::SetFocus(hwnd);
|
||||
}
|
||||
}return 0;
|
||||
|
||||
case WM_KEYDOWN:{
|
||||
switch(a_wparam){
|
||||
case VK_SHIFT:{
|
||||
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) _this->m_key_shift = true;
|
||||
return 0;
|
||||
}
|
||||
case VK_CONTROL:{
|
||||
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) _this->m_key_ctrl = true;
|
||||
return 0;
|
||||
}
|
||||
case VK_UP:{
|
||||
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) _this->key_up();
|
||||
return 0;
|
||||
}
|
||||
case VK_DOWN:{
|
||||
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) _this->key_down();
|
||||
return 0;
|
||||
}
|
||||
case VK_LEFT:{
|
||||
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) _this->key_left();
|
||||
return 0;
|
||||
}
|
||||
case VK_RIGHT:{
|
||||
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) _this->key_right();
|
||||
return 0;
|
||||
}
|
||||
case VK_ESCAPE:{
|
||||
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) _this->key_escape();
|
||||
return 0;
|
||||
}
|
||||
} //end switch(a_wparam)
|
||||
break;
|
||||
}
|
||||
case WM_KEYUP:{
|
||||
switch(a_wparam){
|
||||
case VK_SHIFT:{
|
||||
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) _this->m_key_shift = false;
|
||||
return 0;
|
||||
}
|
||||
case VK_CONTROL:{
|
||||
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) _this->m_key_ctrl = false;
|
||||
return 0;
|
||||
}
|
||||
} //end switch(a_wparam)
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_CLOSE:{
|
||||
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) _this->close();
|
||||
}break; //NOTE : can't be return 0.
|
||||
case WM_DESTROY:wm__destroy(a_hwnd);return 0;
|
||||
}
|
||||
return (DefWindowProc(a_hwnd,a_msg,a_wparam,a_lparam));
|
||||
}
|
||||
static void wm__destroy(HWND a_hwnd) {
|
||||
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
|
||||
if(_this) { //How to be sure that we have a window* ???
|
||||
if(_this->m_hwnd!=a_hwnd) {
|
||||
//::printf("WinTk::Component::wm_destroy : HWND mismatch !\n");
|
||||
}
|
||||
_this->m_hwnd = 0;
|
||||
}
|
||||
::SetWindowLongPtr(a_hwnd,GWLP_USERDATA,LONG_PTR(NULL));
|
||||
}
|
||||
protected:
|
||||
void get_size(HWND a_hwnd,int& a_w,int& a_h){
|
||||
RECT rect;
|
||||
::GetWindowRect(a_hwnd,&rect);
|
||||
a_w = rect.right-rect.left;
|
||||
a_h = rect.bottom-rect.top;
|
||||
}
|
||||
protected:
|
||||
HWND m_hwnd;
|
||||
bool m_key_shift;
|
||||
bool m_key_ctrl;
|
||||
HWND m_focus_hwnd;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user