1 //=============================================================================
2 //
3 //   File : KvsObject_layout.cpp
4 //   Creation date : Fri Now 22 2002 00:50:01 by Szymon Stefanek
5 //
6 //   This file is part of the KVIrc IRC client distribution
7 //   Copyright (C) 2002-2010 Szymon Stefanek (pragma at kvirc dot net)
8 //
9 //   This program is FREE software. You can redistribute it and/or
10 //   modify it under the terms of the GNU General Public License
11 //   as published by the Free Software Foundation; either version 2
12 //   of the License, or (at your option) any later version.
13 //
14 //   This program is distributed in the HOPE that it will be USEFUL,
15 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 //   See the GNU General Public License for more details.
18 //
19 //   You should have received a copy of the GNU General Public License
20 //   along with this program. If not, write to the Free Software Foundation,
21 //   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=============================================================================
24 
25 #define _KVI_DEBUG_CHECK_RANGE_
26 #include "kvi_debug.h"
27 #include "KviLocale.h"
28 #include "KvsObject_layout.h"
29 
30 #include <QGridLayout>
31 
32 // Tables used in $setAlignment & $alignment
33 const char * const align_tbl[] = {
34 	"Left",
35 	"Right",
36 	"HCenter",
37 	"VCenter",
38 	"Center",
39 	"Top",
40 	"Bottom",
41 };
42 
43 const int align_cod[] = {
44 	Qt::AlignLeft,
45 	Qt::AlignRight,
46 	Qt::AlignHCenter,
47 	Qt::AlignVCenter,
48 	Qt::AlignCenter,
49 	Qt::AlignTop,
50 	Qt::AlignBottom,
51 };
52 #define align_num (sizeof(align_tbl) / sizeof(align_tbl[0]))
53 
54 /*
55 	@doc: layout
56 	@keyterms:
57 		layout object class, child widgets
58 	@title:
59 		layout class
60 	@type:
61 		class
62 	@short:
63 		Manages child widget geometry
64 	@inherits:
65 		[class]object[/class]
66 	@description:
67 		The layout is a geometry management tool for child widgets.
68 		You create a layout, give it some widgets to manage and it will layout them
69 		automatically.[br]
70 		The parent of the layout must be the widget for which child widget geometries have to be managed.
71 		A layout is a grid of NxM cells in which you insert child widgets with [classfnc:layout]$addWidget[/classfnc]().[br]
72 		Widgets that must span multiple cells can be added to the layout with [classfnc:layout]$addMultiCellWidget[/classfnc]().[br]
73 	@functions:
74 		!fn: $addWidget(<widget:object widget>,<row:uint>,<column:uint>)
75 		Adds a widget to this layout placing it at position <row>,<column> in the grid
76 		!fn: $addMultiCellWidget(<widget:object widget>,<start_row:uint>,<end_row:uint>,<start_col:uint>,<end_col:uint>)
77 		Adds a widget to this layout spanning multiple grid cells
78 		!fn: $setRowStretch(<row:uint>,<stretch:uint>)
79 		Sets the stretch value for a particular row of this layout.[br]
80 		The <stretch_value> must be a positive integer.[br]
81 		The rows with bigger stretch values will take more space in the layout.
82 		!fn: $setColumnStretch(<column:uint>,<stretch:uint>)
83 		Sets the stretch value for a particular column in this layout.[br]
84 		The <stretch_value> must be a positive integer.[br]
85 		The rows with bigger stretch values will take more space in the layout.
86 		!fn: $addRowSpacing(<row:uint>,<spacing:uint>)
87 		Sets the minimum height of the specified <row> to <spacing> which must be a positive integer
88 		!fn: $addColSpacing(<column:uint>,<spacing:uint>)
89 		Sets the minimum width of the specified <column> to <spacing> which must be a positive integer
90 		!fn: $setSpacing(<spacing:uint>)
91 		Sets the default spacing of the widgets in pixels
92 		!fn: $setMargin(<margin:uint>)
93 		Sets the dimension of the layout margin: the distance from the border to the outermost child widget edges.
94 		!fn: $setAlignment(<w:widget>, <flag1:string>, <flag2:string>, ...)
95 		Sets the alignment for widget w to flags, given as parameters.
96 		Valid flags are: Right, Left, Top, Bottom, HCenter, VCenter, Center
97 		!fn: $setResizeMode(<resize_mode:string>)
98 		Sets the resize mode of the parent widget in relation to this layout.
99 		<mode> can be one of:[br]
100 		[pre]
101 			-Auto: this is the default
102 			-Fixed: the parent widget of this layout is resized to the "sizeHint" value and it cannot be resized by the user.
103 			-Minimum: the minimum size of the parent widget of this layout is set to minimumSize() and it cannot be smaller
104 			-FreeResize: the parent widget of this layout is not constrained at all
105 		[/pre]
106 */
107 
108 KVSO_BEGIN_REGISTERCLASS(KvsObject_layout, "layout", "object")
KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_layout,addWidget)109 KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_layout, addWidget)
110 KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_layout, addMultiCellWidget)
111 KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_layout, setRowStretch)
112 KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_layout, setColumnStretch)
113 KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_layout, addRowSpacing)
114 KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_layout, addColSpacing)
115 KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_layout, setMargin)
116 KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_layout, setSpacing)
117 KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_layout, setResizeMode)
118 KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_layout, setAlignment)
119 KVSO_END_REGISTERCLASS(KvsObject_layout)
120 
121 KVSO_BEGIN_CONSTRUCTOR(KvsObject_layout, KviKvsObject)
122 
123 KVSO_END_CONSTRUCTOR(KvsObject_layout)
124 
125 KVSO_BEGIN_DESTRUCTOR(KvsObject_layout)
126 
127 KVSO_END_DESTRUCTOR(KvsObject_layout)
128 #include <QDebug>
129 bool KvsObject_layout::init(KviKvsRunTimeContext * pContext, KviKvsVariantList *)
130 {
131 	QWidget * w = parentScriptWidget();
132 
133 	if(!w)
134 	{
135 		pContext->warning(__tr2qs_ctx("The parent of a layout must be a widget!", "objects"));
136 		return false;
137 	}
138 
139 	if(w->inherits("QToolBar"))
140 	{
141 		pContext->warning(__tr2qs_ctx("Qt does not support setting layouts on toolbar objects", "objects"));
142 		return false;
143 	}
144 
145 	if(w->inherits("QDockWidget"))
146 	{
147 		pContext->warning(__tr2qs_ctx("Qt does not support setting layouts on dockwidget objects", "objects"));
148 		return false;
149 	}
150 	// If there already is a layout manager installed on this widget, QWidget won't let you install another.
151 	if(w->layout())
152 		delete w->layout();
153 	setObject(new QGridLayout(w));
154 	((QGridLayout *)object())->setVerticalSpacing(0);
155 	((QGridLayout *)object())->setHorizontalSpacing(0);
156 	setObjectName(getName());
157 	return true;
158 }
159 
KVSO_CLASS_FUNCTION(layout,addWidget)160 KVSO_CLASS_FUNCTION(layout, addWidget)
161 {
162 	CHECK_INTERNAL_POINTER(widget())
163 	KviKvsObject * pObject;
164 	kvs_hobject_t hObject;
165 	kvs_uint_t uCol, uRow;
166 	KVSO_PARAMETERS_BEGIN(c)
167 	KVSO_PARAMETER("widget", KVS_PT_HOBJECT, 0, hObject)
168 	KVSO_PARAMETER("row", KVS_PT_UNSIGNEDINTEGER, 0, uRow)
169 	KVSO_PARAMETER("col", KVS_PT_UNSIGNEDINTEGER, 0, uCol)
170 	KVSO_PARAMETERS_END(c)
171 	pObject = KviKvsKernel::instance()->objectController()->lookupObject(hObject);
172 	CHECK_HOBJECT_IS_WIDGET(pObject)
173 	((QGridLayout *)object())->addWidget(((QWidget *)(pObject->object())), uRow, uCol);
174 	return true;
175 }
176 
KVSO_CLASS_FUNCTION(layout,addMultiCellWidget)177 KVSO_CLASS_FUNCTION(layout, addMultiCellWidget)
178 {
179 	CHECK_INTERNAL_POINTER(widget())
180 	KviKvsObject * pObject;
181 	kvs_hobject_t hObject;
182 	kvs_uint_t uStartCol, uStartRow, uEndCol, uEndRow;
183 	KVSO_PARAMETERS_BEGIN(c)
184 	KVSO_PARAMETER("widget", KVS_PT_HOBJECT, 0, hObject)
185 	KVSO_PARAMETER("start_row", KVS_PT_UNSIGNEDINTEGER, 0, uStartRow)
186 	KVSO_PARAMETER("end_row", KVS_PT_UNSIGNEDINTEGER, 0, uEndRow)
187 	KVSO_PARAMETER("start_column", KVS_PT_UNSIGNEDINTEGER, 0, uStartCol)
188 	KVSO_PARAMETER("end_column", KVS_PT_UNSIGNEDINTEGER, 0, uEndCol)
189 	KVSO_PARAMETERS_END(c)
190 	pObject = KviKvsKernel::instance()->objectController()->lookupObject(hObject);
191 	CHECK_HOBJECT_IS_WIDGET(pObject)
192 	((QGridLayout *)object())->addWidget(((QWidget *)(pObject->object())), uStartRow, uStartCol, uEndRow - uStartRow + 1, uEndCol - uStartCol + 1);
193 	return true;
194 }
195 
KVSO_CLASS_FUNCTION(layout,setRowStretch)196 KVSO_CLASS_FUNCTION(layout, setRowStretch)
197 {
198 	CHECK_INTERNAL_POINTER(widget())
199 	kvs_uint_t uRow, uStretch;
200 	KVSO_PARAMETERS_BEGIN(c)
201 	KVSO_PARAMETER("row", KVS_PT_UNSIGNEDINTEGER, 0, uRow)
202 	KVSO_PARAMETER("stretch", KVS_PT_UNSIGNEDINTEGER, 0, uStretch)
203 	KVSO_PARAMETERS_END(c)
204 	((QGridLayout *)object())->setRowStretch(uRow, uStretch);
205 	return true;
206 }
207 
KVSO_CLASS_FUNCTION(layout,setColumnStretch)208 KVSO_CLASS_FUNCTION(layout, setColumnStretch)
209 {
210 	CHECK_INTERNAL_POINTER(widget())
211 	kvs_uint_t uCol, uStretch;
212 	KVSO_PARAMETERS_BEGIN(c)
213 	KVSO_PARAMETER("column", KVS_PT_UNSIGNEDINTEGER, 0, uCol)
214 	KVSO_PARAMETER("stretch", KVS_PT_UNSIGNEDINTEGER, 0, uStretch)
215 	KVSO_PARAMETERS_END(c)
216 	((QGridLayout *)object())->setColumnStretch(uCol, uStretch);
217 	return true;
218 }
219 
KVSO_CLASS_FUNCTION(layout,setMargin)220 KVSO_CLASS_FUNCTION(layout, setMargin)
221 {
222 	CHECK_INTERNAL_POINTER(widget())
223 	kvs_uint_t uMargin;
224 	KVSO_PARAMETERS_BEGIN(c)
225 	KVSO_PARAMETER("margin", KVS_PT_UNSIGNEDINTEGER, 0, uMargin)
226 	KVSO_PARAMETERS_END(c)
227 	((QGridLayout *)object())->setMargin(uMargin);
228 	return true;
229 }
230 
KVSO_CLASS_FUNCTION(layout,setSpacing)231 KVSO_CLASS_FUNCTION(layout, setSpacing)
232 {
233 	CHECK_INTERNAL_POINTER(widget())
234 	kvs_uint_t uSpacing;
235 	KVSO_PARAMETERS_BEGIN(c)
236 	KVSO_PARAMETER("spacing", KVS_PT_UNSIGNEDINTEGER, 0, uSpacing)
237 	KVSO_PARAMETERS_END(c)
238 	((QGridLayout *)object())->setSpacing(uSpacing);
239 	return true;
240 }
241 
KVSO_CLASS_FUNCTION(layout,addRowSpacing)242 KVSO_CLASS_FUNCTION(layout, addRowSpacing)
243 {
244 	CHECK_INTERNAL_POINTER(widget())
245 	kvs_uint_t uSpacing, uRow;
246 	KVSO_PARAMETERS_BEGIN(c)
247 	KVSO_PARAMETER("row", KVS_PT_UNSIGNEDINTEGER, 0, uRow)
248 	KVSO_PARAMETER("spacing", KVS_PT_UNSIGNEDINTEGER, 0, uSpacing)
249 	KVSO_PARAMETERS_END(c)
250 	((QGridLayout *)object())->addItem(new QSpacerItem(0, uSpacing), uRow, 0);
251 	return true;
252 }
253 
KVSO_CLASS_FUNCTION(layout,addColSpacing)254 KVSO_CLASS_FUNCTION(layout, addColSpacing)
255 {
256 	CHECK_INTERNAL_POINTER(widget())
257 	kvs_uint_t uSpacing, uCol;
258 	KVSO_PARAMETERS_BEGIN(c)
259 	KVSO_PARAMETER("column", KVS_PT_UNSIGNEDINTEGER, 0, uCol)
260 	KVSO_PARAMETER("spacing", KVS_PT_UNSIGNEDINTEGER, 0, uSpacing)
261 	KVSO_PARAMETERS_END(c)
262 	((QGridLayout *)object())->addItem(new QSpacerItem(uSpacing, 0), 0, uCol);
263 	return true;
264 }
265 
KVSO_CLASS_FUNCTION(layout,setResizeMode)266 KVSO_CLASS_FUNCTION(layout, setResizeMode)
267 {
268 	CHECK_INTERNAL_POINTER(widget())
269 	QString szMode;
270 	KVSO_PARAMETERS_BEGIN(c)
271 	KVSO_PARAMETER("resize_mode", KVS_PT_STRING, 0, szMode)
272 	KVSO_PARAMETERS_END(c)
273 	QLayout::SizeConstraint r = QLayout::SetDefaultConstraint;
274 	if(KviQString::equalCI(szMode, "FreeResize"))
275 		r = QLayout::SetNoConstraint;
276 	else if(KviQString::equalCI(szMode, "Minimum"))
277 		r = QLayout::SetMinimumSize;
278 	else if(KviQString::equalCI(szMode, "Fixed"))
279 		r = QLayout::SetFixedSize;
280 	else
281 		c->warning(__tr2qs_ctx("Invalid resize mode defaulting to Auto", "objects"));
282 	((QGridLayout *)object())->setSizeConstraint(r);
283 	return true;
284 }
285 
KVSO_CLASS_FUNCTION(layout,setAlignment)286 KVSO_CLASS_FUNCTION(layout, setAlignment)
287 {
288 	CHECK_INTERNAL_POINTER(widget())
289 	QStringList alignment;
290 	KviKvsObject * pObject;
291 	kvs_hobject_t hObject;
292 	KVSO_PARAMETERS_BEGIN(c)
293 	KVSO_PARAMETER("widget", KVS_PT_HOBJECT, 0, hObject)
294 	KVSO_PARAMETER("alignment", KVS_PT_STRINGLIST, KVS_PF_OPTIONAL, alignment)
295 	KVSO_PARAMETERS_END(c)
296 	pObject = KviKvsKernel::instance()->objectController()->lookupObject(hObject);
297 	CHECK_HOBJECT_IS_WIDGET(pObject)
298 	int index = ((QGridLayout *)widget())->indexOf(((QWidget *)(pObject->object())));
299 
300 	if(index == -1)
301 	{
302 		c->warning(__tr2qs_ctx("The widget must be a child of this layout", "objects"));
303 		return true;
304 	}
305 
306 	int align, sum = 0;
307 	for(auto & it : alignment)
308 	{
309 		align = 0;
310 		for(size_t j{}; j < align_num; j++)
311 		{
312 			if(KviQString::equalCI(it, align_tbl[j]))
313 			{
314 				align = align_cod[j];
315 				break;
316 			}
317 		}
318 		if(align)
319 			sum = sum | align;
320 		else
321 			c->warning(__tr2qs_ctx("Unknown alignment: '%Q'", "objects"), &it);
322 	}
323 
324 	if(widget())
325 		((QGridLayout *)widget())->setAlignment(((QWidget *)(pObject->object())), (Qt::Alignment)sum);
326 	return true;
327 }
328