summaryrefslogtreecommitdiff
path: root/plugins/TabSRMM/src/sidebar.h
blob: 32fd8669ea994b054eab899b96826bd7252682b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
/*
 * astyle --force-indent=tab=4 --brackets=linux --indent-switches
 *		  --pad=oper --one-line=keep-blocks  --unpad=paren
 *
 * Miranda NG: the free IM client for Microsoft* Windows*
 *
 * Copyright 2000-2009 Miranda ICQ/IM project,
 * all portions of this codebase are copyrighted to the people
 * listed in contributors.txt.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * you should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * part of tabSRMM messaging plugin for Miranda.
 *
 * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors
 *
 * the contact switch bar on the left (or right) side
 *
 */

#ifndef __SIDEBAR_H
#define  __SIDEBAR_H

struct TSideBarNotify
{
	NMHDR 				nmHdr;
	const TWindowData*	dat;
};
/* layout description structure */

struct TSideBarLayout
{
	TCHAR		szName[50];					// everything wants a name...
	LONG		width;						// width of the switchbar element (a single button)
	LONG		height;						// height of a single switchbar element
	DWORD		dwFlags;					// flags, obviously :)

	/*
	 * the following 4 items define pointers to the actual renderer functions for that sidebar layout
	 * a default is always provided, however, it has been designed to be easily extendible without
	 * rewriting lots of code just in order to change how the switchbar items look like.
	 */
	void		(__fastcall *pfnContentRenderer)(const HDC hdc, const RECT *rc, const CSideBarButton *item);
	void		(__fastcall *pfnBackgroundRenderer)(const HDC hdc, const RECT *rc, const CSideBarButton *item);
	const SIZE&	(__fastcall *pfnMeasureItem)(CSideBarButton *item);
	void		(__fastcall *pfnLayout)(const CSideBar *sideBar, RECT *rc);
	UINT		uId;						// numeric id by which the layout is identified. basically, the index into the array.
};

class CSideBar;

class CSideBarButton
{
public:
	CSideBarButton(const UINT id, CSideBar *sideBar);
	CSideBarButton(const TWindowData *dat, CSideBar *sideBar);
	~CSideBarButton();

	LONG  						getHeight() const 			{ return(m_sz.cy); }
	const SIZE&					getSize() const 			{ return(m_sz); }
	void						setSize(const SIZE& newSize){ m_sz = newSize; }
	const bool					isTopAligned() const 		{ return(m_isTopAligned); }
	const HWND					getHwnd() const 			{ return(m_hwnd); }
	const UINT					getID() const 				{ return(m_id); }
	const HANDLE				getContactHandle() const 	{ return(m_dat->hContact); }
	const TWindowData*	getDat() const 				{ return(m_dat); }
	const TSideBarLayout*		getLayout() const 			{ return(m_sideBarLayout); }

	void 						RenderThis					(const HDC hdc) const;
	void 						renderIconAndNick			(const HDC hdc, const RECT *rcItem) const;
	int							testCloseButton() const;
	void 						Show(const int showCmd) const;
	void						activateSession() const;
	const SIZE&					measureItem();
	void						setLayout(const TSideBarLayout *newLayout);
	void						invokeContextMenu();

public:
	CSideBar* 					m_sideBar;
	const	MButtonCtrl*		m_buttonControl;						// private data struct of the Win32 button object
private:
	void						_create();
private:
	const TSideBarLayout*		m_sideBarLayout;
	HWND						m_hwnd;									// window handle for the TSButton object
	const 						TWindowData*  m_dat;				// session data
	UINT						m_id;									// control id
	bool						m_isTopAligned;
	SIZE						m_sz;
};

typedef std::vector<CSideBarButton *>::iterator ButtonIterator;

class CSideBar
{
public:
	enum {
		NR_LAYOUTS = 4
	};

	enum {
		/* layout ids. index into m_layouts[] */

		SIDEBARLAYOUT_VERTICAL = 0,
		SIDEBARLAYOUT_NORMAL = 1,
		SIDEBARLAYOUT_COMPLEX = 2,
		SIDEBARLAYOUT_LARGE = 3,

		/* flags */

		SIDEBARORIENTATION_LEFT = 8,
		SIDEBARORIENTATION_RIGHT = 16,

		SIDEBARLAYOUT_DYNHEIGHT = 32,
		SIDEBARLAYOUT_VERTICALORIENTATION = 64,
		SIDEBARLAYOUT_NOCLOSEBUTTONS = 128
	};

	enum {
		SIDEBAR_GAP = 2									// gap between sidebar container window and content tab sheet border
	};

	CSideBar(TContainerData *pContainer);
	~CSideBar();

	void						Init						(const bool fForce = false);
	void						addSession					(const TWindowData *dat, int position = -1);
	HRESULT						removeSession				(const TWindowData *dat);
	void						updateSession				(const TWindowData *dat);

	void						processScrollerButtons		(UINT cmd);
	void						Layout						(const RECT *rc = 0, bool fOnlyCalc = false);
	void						setVisible					(bool fNewVisibility);
	void 						showAll						(int showCmd);

	const LONG 					getWidth() const 			{ return(m_isVisible ? m_width + SIDEBAR_GAP : 0); }
	const DWORD					getFlags() const			{ return(m_dwFlags); }
	const TContainerData*		getContainer() const 		{ return(m_pContainer); }
	const bool					isActive() const 			{ return(m_isActive); }
	const bool					isVisible() const 			{ return(m_isVisible); }
	const CSideBarButton* 		getActiveItem() const 		{ return(m_activeItem); }
	const CSideBarButton*		getScrollUp() const			{ return(m_up); }
	const CSideBarButton*		getScrollDown() const		{ return(m_down); }
	bool						isSkinnedContainer() const 	{ return(CSkin::m_skinEnabled ? true : false); }
	const UINT					getLayoutId() const 		{ return(m_uLayout); }
	void						invalidateButton			(const TWindowData *dat);

	const CSideBarButton* 		setActiveItem				(const CSideBarButton *newItem)
	{
		CSideBarButton *oldItem = m_activeItem;
		m_activeItem = const_cast<CSideBarButton *>(newItem);
		if (oldItem)
			::InvalidateRect(oldItem->getHwnd(), NULL, FALSE);
		::InvalidateRect(m_activeItem->getHwnd(), NULL, FALSE);
		scrollIntoView(m_activeItem);
		return(oldItem);
	}
	/**
	 * this item has its close button currently hovered
	 * @param item: the CSideBarButton* which is hovered
	 */
	void								setHoveredClose					(CSideBarButton* item)
	{
		m_hoveredClose = item;
	}
	HWND								getScrollWnd() const 			{ return(m_hwndScrollWnd); }
	const CSideBarButton*				getHoveredClose() const 		{ return(m_hoveredClose); }
	const CSideBarButton* 		 		setActiveItem					(const TWindowData *dat);

	static const TSideBarLayout* 		getLayouts						(int& uLayoutCount)
	{
		uLayoutCount = NR_LAYOUTS;
		return(m_layouts);
	}
	void								scrollIntoView					(const CSideBarButton *item = 0);
	void								resizeScrollWnd					(LONG x, LONG y, LONG width, LONG height) const;
	static LRESULT CALLBACK 			wndProcStub						(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

private:
	void								createScroller();
	void								destroyScroller();
	void								populateAll();
	void								removeAll();
	void								Invalidate();
	ButtonIterator 						findSession						(const TWindowData *dat);
	ButtonIterator						findSession						(const HANDLE hContact);

	LRESULT CALLBACK					wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

private:
	HWND								m_hwndScrollWnd;
	std::vector<CSideBarButton*> 		m_buttonlist;							// our list of buttons
	TContainerData*						m_pContainer;							// our master and commander...
	LONG								m_width;								// required width of the bar (m_elementWidth + padding)
	DWORD								m_dwFlags;
	CSideBarButton*						m_up, *m_down;							// the scroller buttons (up down)
	CSideBarButton*						m_activeItem;							// active button item (for highlighting)
	const CSideBarButton*				m_hoveredClose;							// item which must display an active close button
	LONG								m_topHeight, m_bottomHeight;
	LONG								m_firstVisibleOffset, m_totalItemHeight;
	int									m_iTopButtons, m_iBottomButtons;
	LONG								m_elementHeight, m_elementWidth;		// width / height for a single element.
																				// can be dynamic (see measeureItem() in CSideBarButtonItem
	bool								m_isActive;								// the sidebar is active (false, if it does _nothing at all_
	bool								m_isVisible;							// visible aswell (not collapsed)
	TSideBarLayout*						m_currentLayout;						// the layout in use. will be passed to new button items
	UINT								m_uLayout;								// layout id number, currently in use

private:
	/*
	 * layouts. m_layouts[] is static and contains layout descriptions
	 * renderer functions are static aswell
	 */
	static					TSideBarLayout 	m_layouts[NR_LAYOUTS];
	static void __fastcall  m_DefaultBackgroundRenderer(const HDC hdc, const RECT *rc, const CSideBarButton *item);
	static void __fastcall  m_DefaultContentRenderer(const HDC hdc, const RECT *rc, const CSideBarButton *item);
	static void __fastcall  m_AdvancedContentRenderer(const HDC hdc, const RECT *rc, const CSideBarButton *item);
	
	static const SIZE& __fastcall	m_measureAdvancedVertical(CSideBarButton *item);
};

inline void	CSideBarButton::setLayout(const TSideBarLayout *newLayout)
{
	m_sideBarLayout = newLayout;
}

#endif