/* * Copyright 2003 Martin Fuchs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // // Explorer clone // // window.h // // Martin Fuchs, 23.07.2003 // #include #include #include typedef set WindowSet; /* Classes are declared using "struct", not "class" because the default access mode is "public". This way we can list the member functions in a natural order without explicitly specifying any access mode at the begin of the definition. First are public constructors and destructor, then public member functions. After that we list protected member varibables and functions. If needed, private implemenation varibales and functions are positioned at the end. */ /** Class Window is the base class for several C++ window wrapper classes. Window objects are allocated from the heap. They are automatically freed when the window gets destroyed. */ struct Window : public WindowHandle { Window(HWND hwnd); virtual ~Window(); typedef map WindowMap; typedef Window* (*CREATORFUNC)(HWND, const void*); typedef Window* (*CREATORFUNC_NO_INFO)(HWND); static HWND Create(CREATORFUNC creator, DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int w, int h, HWND hwndParent=0, HMENU hMenu=0, LPVOID lpParam=0); static HWND Create(CREATORFUNC creator, const void* info, DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int w, int h, HWND hwndParent=0, HMENU hMenu=0, LPVOID lpParam=0); static Window* create_mdi_child(HWND hmdiclient, const MDICREATESTRUCT& mcs, CREATORFUNC creator, const void* info=NULL); static LRESULT CALLBACK WindowWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam); static Window* get_window(HWND hwnd); #ifndef _MSC_VER template static CLASS* get_window(HWND hwnd) {return static_cast(get_window(hwnd));} #define GET_WINDOW(CLASS, hwnd) Window::get_window(hwnd) #endif static void register_pretranslate(HWND hwnd); static void unregister_pretranslate(HWND hwnd); static BOOL pretranslate_msg(LPMSG pmsg); static void register_dialog(HWND hwnd); static void unregister_dialog(HWND hwnd); static BOOL dispatch_dialog_msg(LPMSG pmsg); static int MessageLoop(); LRESULT SendParent(UINT nmsg, WPARAM wparam=0, LPARAM lparam=0); LRESULT PostParent(UINT nmsg, WPARAM wparam=0, LPARAM lparam=0); static void CancelModes(HWND hwnd=0); protected: virtual LRESULT Init(LPCREATESTRUCT pcs); // WM_CREATE processing virtual LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); virtual int Command(int id, int code); // WM_COMMAND processing virtual int Notify(int id, NMHDR* pnmh); // WM_NOTIFY processing static WindowMap s_wnd_map; static const void* s_new_info; static CREATORFUNC s_window_creator; struct StaticWindowData { CritSect _map_crit_sect; CritSect _create_crit_sect; }; static StaticWindowData& GetStaticWindowData(); // MDI child creation static HHOOK s_hcbtHook; static LRESULT CALLBACK CBTHookProc(int code, WPARAM wparam, LPARAM lparam); static WindowSet s_pretranslate_windows; static WindowSet s_dialogs; }; #ifdef _MSC_VER template struct GetWindowHelper { static CLASS* get_window(HWND hwnd) { return static_cast(Window::get_window(hwnd)); } }; #define GET_WINDOW(CLASS, hwnd) GetWindowHelper::get_window(hwnd) #endif template struct TypeCheck { static CLASS* dyn_cast(Window* wnd) {return dynamic_cast(wnd);} }; #define WINDOW_DYNAMIC_CAST(CLASS, hwnd) \ TypeCheck::dyn_cast(Window::get_window(hwnd)) /** SubclassedWindow is used to wrap already existing window handles into C++ Window objects. To construct a object, use the "new" operator to put it in the heap. It is automatically freed, when the window gets destroyed. */ struct SubclassedWindow : public Window { typedef Window super; SubclassedWindow(HWND); protected: WNDPROC _orgWndProc; LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); }; template struct WindowCreator { static WND_CLASS* window_creator(HWND hwnd) { return new WND_CLASS(hwnd); } }; #define WINDOW_CREATOR(WND_CLASS) \ (Window::CREATORFUNC) WindowCreator::window_creator template struct WindowCreatorInfo { static WND_CLASS* window_creator(HWND hwnd, const void* info) { return new WND_CLASS(hwnd, *static_cast(info)); } }; #define WINDOW_CREATOR_INFO(WND_CLASS, INFO_CLASS) \ (Window::CREATORFUNC) WindowCreatorInfo::window_creator /** WindowClass is a neat wrapper for RegisterClassEx(). Just construct a WindowClass object, override the attributes you want to change, then call Register() or simply request the ATOM value to register the window class. You don't have to worry calling Register() more than once. It checks if, the class has already been registered. */ struct WindowClass : public WNDCLASSEX { WindowClass(LPCTSTR classname, UINT style=0, WNDPROC wndproc=Window::WindowWndProc); ATOM Register() { if (!_atomClass) _atomClass = RegisterClassEx(this); return _atomClass; } operator ATOM() {return Register();} // return LPCTSTR for the CreateWindowEx() parameter operator LPCTSTR() {return (LPCTSTR)(int)Register();} protected: ATOM _atomClass; }; /// window class with gray background color struct BtnWindowClass : public WindowClass { BtnWindowClass(LPCTSTR classname, UINT style=0, WNDPROC wndproc=Window::WindowWndProc) : WindowClass(classname, style, wndproc) { hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); } }; /// window class with specified icon from resources struct IconWindowClass : public WindowClass { IconWindowClass(LPCTSTR classname, UINT nid, UINT style=0, WNDPROC wndproc=Window::WindowWndProc); }; // private message constants #define PM_DISPATCH_COMMAND (WM_APP+0x00) #define PM_TRANSLATE_MSG (WM_APP+0x01) #define SPLIT_WIDTH 5 #define DEFAULT_SPLIT_POS 300 #define COLOR_SPLITBAR LTGRAY_BRUSH /// menu info structure for MDI child windows struct MenuInfo { HMENU _hMenuView; HMENU _hMenuOptions; }; #define PM_FRM_GET_MENUINFO (WM_APP+0x02) #define Frame_GetMenuInfo(hwnd) ((MenuInfo*)SNDMSG(hwnd, PM_FRM_GET_MENUINFO, 0, 0)) /** Class ChildWindow represents MDI child windows. It is used with class MainFrame. */ struct ChildWindow : public Window { typedef Window super; ChildWindow(HWND hwnd); static ChildWindow* create(HWND hmdiclient, const RECT& rect, CREATORFUNC creator, LPCTSTR classname, LPCTSTR title=NULL, const void* info=NULL); protected: LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); virtual void resize_children(int cx, int cy); protected: MenuInfo*_menu_info; WindowHandle _left_hwnd; WindowHandle _right_hwnd; int _focus_pane; // 0: left 1: right int _split_pos; int _last_split; }; /** PreTranslateWindow is used to register windows to be called by Window::pretranslate_msg(). This way you get PM_TRANSLATE_MSG messages before the message loop dispatches messages. You can then for example use TranslateAccelerator() to implement key shortcuts. */ struct PreTranslateWindow : public Window { typedef Window super; PreTranslateWindow(HWND); ~PreTranslateWindow(); }; /** The class Dialog implements modeless dialogs, which are managed by Window::dispatch_dialog_msg() in Window::MessageLoop(). A Dialog object should be constructed by calling Window::Create() and specifying the class using the WINDOW_CREATOR() macro. */ struct Dialog : public Window { typedef Window super; Dialog(HWND); ~Dialog(); }; /** This class constructs button controls. The button will remain existent when the C++ Button object is destroyed. There is no conjunction between C++ object and windows control life time. */ struct Button : public WindowHandle { Button(HWND parent, LPCTSTR text, int left, int top, int width, int height, int id, DWORD flags=WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, DWORD exStyle=0); }; /** This class constructs static controls. The control will remain existent when the C++ object is destroyed. There is no conjunction between C++ object and windows control life time. */ struct Static : public WindowHandle { Static(HWND parent, LPCTSTR text, int left, int top, int width, int height, int id, DWORD flags=WS_VISIBLE|WS_CHILD|SS_SIMPLE, DWORD ex_flags=0); }; /* // control color message routing for ColorStatic and HyperlinkCtrl #define PM_DISPATCH_CTLCOLOR (WM_APP+0x07) template struct CtlColorParent : public BASE { typedef BASE super; CtlColorParent(HWND hwnd) : super(hwnd) {} LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) { switch(nmsg) { case WM_CTLCOLOR: case WM_CTLCOLORBTN: case WM_CTLCOLORDLG: case WM_CTLCOLORSCROLLBAR: case WM_CTLCOLORSTATIC: { HWND hctl = (HWND) lparam; return SendMessage(hctl, PM_DISPATCH_CTLCOLOR, wparam, nmsg); } default: return super::WndProc(nmsg, wparam, lparam); } } }; */ // owner draw message routing for ColorButton and PictureButton #define PM_DISPATCH_DRAWITEM (WM_APP+0x08) template struct OwnerDrawParent : public BASE { typedef BASE super; OwnerDrawParent(HWND hwnd) : super(hwnd) {} LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) { switch(nmsg) { case WM_DRAWITEM: if (wparam) { // should there be drawn a control? HWND hctl = GetDlgItem(_hwnd, wparam); if (hctl) return SendMessage(hctl, PM_DISPATCH_DRAWITEM, wparam, lparam); } /*else // or is it a menu entry? ; */ return 0; default: return super::WndProc(nmsg, wparam, lparam); } } }; /** Subclass button controls to draw them by using PM_DISPATCH_DRAWITEM The owning window should use the OwnerDrawParent template to route owner draw messages to the buttons. */ struct OwnerdrawnButton : public SubclassedWindow { typedef SubclassedWindow super; OwnerdrawnButton(HWND hwnd) : super(hwnd) {} protected: LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); void DrawGrayText(LPDRAWITEMSTRUCT dis, LPRECT pRect, LPCTSTR text, int dt_flags); virtual void DrawItem(LPDRAWITEMSTRUCT dis) = 0; }; /** Subclass button controls to paint colored text labels. The owning window should use the OwnerDrawParent template to route owner draw messages to the buttons. */ /* not yet used struct ColorButton : public OwnerdrawnButton { typedef OwnerdrawnButton super; ColorButton(HWND hwnd, COLORREF textColor) : super(hwnd), _textColor(textColor) {} protected: virtual void DrawItem(LPDRAWITEMSTRUCT dis); COLORREF _textColor; }; */ /** Subclass button controls to paint pictures left to the labels. The buttons should have set the style bit BS_OWNERDRAW. The owning window should use the OwnerDrawParent template to route owner draw messages to the buttons. */ struct PictureButton : public OwnerdrawnButton { typedef OwnerdrawnButton super; PictureButton(HWND hwnd, HICON hIcon, HBRUSH hbrush=GetSysColorBrush(COLOR_BTNFACE), bool flat=false) : super(hwnd), _hIcon(hIcon), _hBrush(hbrush), _flat(flat) { } protected: virtual void DrawItem(LPDRAWITEMSTRUCT dis); HICON _hIcon; HBRUSH _hBrush; bool _flat; }; struct ToolTip : public WindowHandle { typedef WindowHandle super; ToolTip(HWND owner); void activate(BOOL active=TRUE) { SendMessage(_hwnd, TTM_ACTIVATE, active, 0); } void add(HWND hparent, HWND htool, LPCTSTR txt=LPSTR_TEXTCALLBACK) { TOOLINFO ti = { sizeof(TOOLINFO), TTF_SUBCLASS|TTF_IDISHWND/*|TTF_TRANSPARENT*/, hparent, (UINT)htool, {0,0,0,0}, 0, 0, 0 }; ti.lpszText = (LPTSTR) txt; SendMessage(_hwnd, TTM_ADDTOOL, 0, (LPARAM)&ti); } };