1 /*
2 # PostgreSQL Database Modeler (pgModeler)
3 #
4 # Copyright 2006-2020 - Raphael Araújo e Silva <raphael@pgmodeler.io>
5 #
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation version 3.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # The complete text of GPLv3 is at LICENSE file on source code root directory.
16 # Also, you can get the complete GNU General Public License at <http://www.gnu.org/licenses/>
17 */
18 
19 #include "attributestoggleritem.h"
20 #include <QApplication>
21 #include <QDesktopWidget>
22 #include <QScreen>
23 #include "baseobjectview.h"
24 
25 QPolygonF AttributesTogglerItem::btn_polygons[7];
26 
AttributesTogglerItem(QGraphicsItem * parent)27 AttributesTogglerItem::AttributesTogglerItem(QGraphicsItem *parent) : RoundedRectItem(parent)
28 {
29 	createButtonPolygons();
30 	this->setRoundedCorners(RoundedRectItem::BottomLeftCorner | RoundedRectItem::BottomRightCorner);
31 	sel_rect = new QGraphicsRectItem;
32 
33 	for(unsigned arr_id = 0; arr_id < 7; arr_id++)
34 	{
35 		buttons[arr_id] = new QGraphicsPolygonItem;
36 		buttons[arr_id]->setPolygon(btn_polygons[arr_id]);
37 		btns_selected[arr_id] = false;
38 	}
39 
40 	buttons[AttribsExpandBtn]->setToolTip(tr("Expands the currently collapsed section of the object"));
41 	buttons[AttribsCollapseBtn]->setToolTip(tr("Collapses the currently expanded section of the object"));
42 	buttons[NextAttribsPageBtn]->setToolTip(tr("Displays the next attributes page"));
43 	buttons[PrevAttribsPageBtn]->setToolTip(tr("Displays the previous attributes page"));
44 	buttons[NextExtAttribsPageBtn]->setToolTip(tr("Displays the next extended attributes page"));
45 	buttons[PrevExtAttribsPageBtn]->setToolTip(tr("Displays the previous extended attributes page"));
46 	buttons[PaginationTogglerBtn]->setToolTip(tr("Toggles the attributes pagination on the object"));
47 
48 	has_ext_attribs = false;
49 	pagination_enabled = false;
50 	collapse_mode = CollapseMode::NotCollapsed;
51 	btns_width = btns_height = 0;
52 
53 	for(unsigned idx = 0; idx < 2; idx++)
54 		current_page[idx] = max_pages[idx] = 0;
55 
56 	configureButtonsState();
57 }
58 
~AttributesTogglerItem()59 AttributesTogglerItem::~AttributesTogglerItem()
60 {
61 	for(unsigned arr_id = 0; arr_id < 7; arr_id++)
62 		delete buttons[arr_id];
63 
64 	delete sel_rect;
65 }
66 
setButtonsBrush(const QBrush & brush)67 void AttributesTogglerItem::setButtonsBrush(const QBrush &brush)
68 {
69 	for(unsigned arr_id = 0; arr_id < 7; arr_id++)
70 		buttons[arr_id]->setBrush(brush);
71 }
72 
setButtonsPen(const QPen & pen)73 void AttributesTogglerItem::setButtonsPen(const QPen &pen)
74 {
75 	for(unsigned arr_id = 0; arr_id < 7; arr_id++)
76 		buttons[arr_id]->setPen(pen);
77 }
78 
setRect(const QRectF & rect)79 void AttributesTogglerItem::setRect(const QRectF &rect)
80 {
81 	configureButtons(rect);
82 }
83 
setCollapseMode(CollapseMode coll_mode)84 void AttributesTogglerItem::setCollapseMode(CollapseMode coll_mode)
85 {
86 	//Avoiding setting up extended attributes collapsed when the toggler is configured to not having extended attribs
87 	if(!has_ext_attribs && coll_mode == CollapseMode::ExtAttribsCollapsed)
88 		collapse_mode = CollapseMode::NotCollapsed;
89 	else
90 		collapse_mode = coll_mode;
91 
92 	configureButtonsState();
93 }
94 
setButtonSelected(const QPointF & pnt,bool clicked)95 void AttributesTogglerItem::setButtonSelected(const QPointF &pnt, bool clicked)
96 {
97 	QRectF rect;
98 	double h_spacing = 4 * BaseObjectView::HorizSpacing;
99 	unsigned coll_mode = static_cast<unsigned>(collapse_mode), section_id = 0;
100 
101 	this->setToolTip("");
102 	clearButtonsSelection();
103 
104 	for(unsigned arr_id = 0; arr_id < 7; arr_id++)
105 	{
106 		rect.setSize(QSizeF(buttons[arr_id]->boundingRect().width() + h_spacing, this->boundingRect().height()));
107 		rect.moveTo(buttons[arr_id]->pos().x() - (h_spacing/2), 0);
108 		btns_selected[arr_id] = rect.contains(pnt) && buttons[arr_id]->isVisible();
109 
110 		if(btns_selected[arr_id])
111 		{
112 			this->setToolTip(buttons[arr_id]->toolTip());
113 
114 			if(clicked)
115 			{
116 				if(arr_id == AttribsExpandBtn || arr_id == AttribsCollapseBtn)
117 				{
118 					if(arr_id == AttribsExpandBtn)
119 						coll_mode++;
120 					else if(arr_id == AttribsCollapseBtn)
121 						coll_mode--;
122 
123 					if(!has_ext_attribs && static_cast<CollapseMode>(coll_mode) == CollapseMode::ExtAttribsCollapsed)
124 						coll_mode += (arr_id == AttribsExpandBtn ? 1 : -1);
125 
126 					if(coll_mode > enum_cast(CollapseMode::NotCollapsed))
127 						collapse_mode = (arr_id == AttribsExpandBtn ? CollapseMode::NotCollapsed : CollapseMode::AllAttribsCollapsed);
128 					else
129 						collapse_mode = static_cast<CollapseMode>(coll_mode);
130 				}
131 				else if(arr_id == PaginationTogglerBtn)
132 				{
133 					pagination_enabled = !pagination_enabled;
134 				}
135 				else
136 				{
137 					if(arr_id == PrevAttribsPageBtn || arr_id == NextAttribsPageBtn)
138 						section_id = BaseTable::AttribsSection;
139 					else
140 						section_id = BaseTable::ExtAttribsSection;
141 
142 					if(max_pages[section_id] != 0)
143 					{
144 						if(arr_id == PrevAttribsPageBtn || arr_id == PrevExtAttribsPageBtn)
145 							current_page[section_id]--;
146 						else
147 							current_page[section_id]++;
148 
149 						if(current_page[section_id] >= max_pages[section_id])
150 							current_page[section_id] = (arr_id == PrevAttribsPageBtn || arr_id == PrevExtAttribsPageBtn ? 0 : max_pages[section_id] - 1);
151 					}
152 				}
153 
154 				configureButtons(this->rect());
155 				clearButtonsSelection();
156 				configureButtonsState();
157 
158 				if(arr_id == PaginationTogglerBtn)
159 					emit s_paginationToggled(pagination_enabled);
160 				else if(arr_id == AttribsExpandBtn || arr_id == AttribsCollapseBtn)
161 					emit s_collapseModeChanged(collapse_mode);
162 				else
163 					emit s_currentPageChanged(section_id, current_page[section_id]);
164 			}
165 			else
166 			{
167 				//Configuring the selection rectangle if the arrows isn't clicked
168 				QRectF rect;
169 				QSizeF size = QSizeF(buttons[AttribsExpandBtn]->boundingRect().size().width() + (2 * BaseObjectView::HorizSpacing),
170 														 btns_height + BaseObjectView::VertSpacing);
171 				double px = 0, py = 0, arr_x = buttons[arr_id]->pos().x();
172 
173 				rect.setSize(size);
174 				px = arr_x - (((arr_x + size.width()) - (arr_x + buttons[arr_id]->boundingRect().width()))/2);
175 				py = (this->boundingRect().size().height() - size.height())/2.5;
176 
177 				sel_rect->setBrush(BaseObjectView::getFillStyle(Attributes::ObjSelection));
178 				sel_rect->setPen(BaseObjectView::getBorderStyle(Attributes::ObjSelection));
179 				sel_rect->setRect(rect);
180 				sel_rect->setPos(px, py);
181 			}
182 
183 			break;
184 		}
185 	}
186 }
187 
configureButtonsState()188 void AttributesTogglerItem::configureButtonsState()
189 {
190 	buttons[AttribsExpandBtn]->setOpacity(collapse_mode == CollapseMode::ExtAttribsCollapsed ||
191 																				 collapse_mode == CollapseMode::AllAttribsCollapsed? 1 : ButtonMinOpacity);
192 
193 	buttons[AttribsCollapseBtn]->setOpacity(collapse_mode == CollapseMode::ExtAttribsCollapsed ||
194 																					 collapse_mode == CollapseMode::NotCollapsed ? 1 : ButtonMinOpacity);
195 
196 	buttons[PrevAttribsPageBtn]->setOpacity(max_pages[BaseTable::AttribsSection] != 0 && current_page[BaseTable::AttribsSection] > 0 ? 1 : ButtonMinOpacity);
197 	buttons[NextAttribsPageBtn]->setOpacity(max_pages[BaseTable::AttribsSection] != 0 &&
198 																					current_page[BaseTable::AttribsSection] < max_pages[BaseTable::AttribsSection] - 1 ? 1 : ButtonMinOpacity);
199 
200 	buttons[PrevExtAttribsPageBtn]->setOpacity(has_ext_attribs && max_pages[BaseTable::ExtAttribsSection] != 0 && current_page[BaseTable::ExtAttribsSection] > 0 ? 1 : ButtonMinOpacity);
201 	buttons[NextExtAttribsPageBtn]->setOpacity(has_ext_attribs && max_pages[BaseTable::ExtAttribsSection] != 0 &&
202 																						 current_page[BaseTable::ExtAttribsSection] < max_pages[BaseTable::ExtAttribsSection] - 1 ? 1 : ButtonMinOpacity);
203 
204 	buttons[PrevAttribsPageBtn]->setVisible(pagination_enabled);
205 	buttons[NextAttribsPageBtn]->setVisible(pagination_enabled);
206 	buttons[PrevExtAttribsPageBtn]->setVisible(pagination_enabled);
207 	buttons[NextExtAttribsPageBtn]->setVisible(pagination_enabled);
208 }
209 
setHasExtAttributes(bool value)210 void AttributesTogglerItem::setHasExtAttributes(bool value)
211 {
212 	has_ext_attribs = value;
213 	configureButtonsState();
214 }
215 
setPaginationEnabled(bool value,bool hide_pag_toggler)216 void AttributesTogglerItem::setPaginationEnabled(bool value, bool hide_pag_toggler)
217 {
218 	buttons[PaginationTogglerBtn]->setVisible(!hide_pag_toggler);
219 	pagination_enabled = value;
220 	configureButtons(this->boundingRect());
221 	configureButtonsState();
222 }
223 
setPaginationValues(unsigned section_id,unsigned curr_page,unsigned max_page)224 void AttributesTogglerItem::setPaginationValues(unsigned section_id, unsigned curr_page, unsigned max_page)
225 {
226 	if(!pagination_enabled || section_id > BaseTable::ExtAttribsSection)
227 		return;
228 
229 	if(curr_page > max_page)
230 		current_page[section_id] = max_pages[section_id] = max_page;
231 	else
232 	{
233 		current_page[section_id] = curr_page;
234 		max_pages[section_id] = max_page;
235 	}
236 }
237 
clearButtonsSelection()238 void AttributesTogglerItem::clearButtonsSelection()
239 {
240 	for(unsigned arr_id = 0; arr_id < 7; arr_id++)
241 		btns_selected[arr_id] = false;
242 
243 	this->update();
244 }
245 
getButtonsWidth()246 double AttributesTogglerItem::getButtonsWidth()
247 {
248 	return btns_width;
249 }
250 
getButtonsHeight()251 double AttributesTogglerItem::getButtonsHeight()
252 {
253 	return btns_height;
254 }
255 
configureButtons(const QRectF & rect)256 void AttributesTogglerItem::configureButtons(const QRectF &rect)
257 {
258 	double arr_width = 0, px = 0,
259 			h_spacing = 6 * BaseObjectView::HorizSpacing,
260 			height =  4 * BaseObjectView::VertSpacing;
261 	QRectF new_rect = rect;
262 
263 	btns_height = btn_polygons[PrevAttribsPageBtn].boundingRect().height();
264 	height += btns_height;
265 
266 	if(pagination_enabled)
267 	{
268 		arr_width = btn_polygons[PrevAttribsPageBtn].boundingRect().width() +
269 								btn_polygons[NextAttribsPageBtn].boundingRect().width() +
270 								btn_polygons[PrevExtAttribsPageBtn].boundingRect().width() +
271 								btn_polygons[NextExtAttribsPageBtn].boundingRect().width() +
272 								(4 * h_spacing);
273 	}
274 
275 	arr_width += btn_polygons[AttribsCollapseBtn].boundingRect().width() +
276 							 btn_polygons[AttribsExpandBtn].boundingRect().width() + (2 * h_spacing);
277 
278 	if(buttons[PaginationTogglerBtn]->isVisible())
279 		arr_width += btn_polygons[AttribsExpandBtn].boundingRect().width() + h_spacing;
280 
281 	btns_width = arr_width;
282 	new_rect.setHeight(height);
283 	RoundedRectItem::setRect(new_rect);
284 
285 	px = (new_rect.width() - arr_width + h_spacing)/2;
286 
287 	if(buttons[PaginationTogglerBtn]->isVisible())
288 	{
289 		buttons[PaginationTogglerBtn]->setPos(px, (new_rect.height() - buttons[PaginationTogglerBtn]->boundingRect().height())/2);
290 		px += buttons[PaginationTogglerBtn]->boundingRect().width() + h_spacing;
291 
292 		if(pagination_enabled)
293 		{
294 			buttons[PrevExtAttribsPageBtn]->setPos(px, (new_rect.height() - buttons[PrevExtAttribsPageBtn]->boundingRect().height())/2);
295 			px += buttons[PrevExtAttribsPageBtn]->boundingRect().width() + h_spacing;
296 
297 			buttons[PrevAttribsPageBtn]->setPos(px, (new_rect.height() - buttons[PrevAttribsPageBtn]->boundingRect().height())/2);
298 			px += buttons[PrevAttribsPageBtn]->boundingRect().width() + h_spacing;
299 
300 			buttons[NextAttribsPageBtn]->setPos(px, (new_rect.height() - buttons[NextAttribsPageBtn]->boundingRect().height())/2);
301 			px += buttons[PrevExtAttribsPageBtn]->boundingRect().width() + h_spacing;
302 
303 			buttons[NextExtAttribsPageBtn]->setPos(px, (new_rect.height() - buttons[NextExtAttribsPageBtn]->boundingRect().height())/2);
304 			px += buttons[NextExtAttribsPageBtn]->boundingRect().width() + h_spacing;
305 		}
306 	}
307 
308 	buttons[AttribsCollapseBtn]->setPos(px, (new_rect.height() - buttons[AttribsCollapseBtn]->boundingRect().height())/2);
309 	px += buttons[AttribsCollapseBtn]->boundingRect().width() + h_spacing * 0.80;
310 
311 	buttons[AttribsExpandBtn]->setPos(px, (new_rect.height() - buttons[AttribsExpandBtn]->boundingRect().height())/2);
312 }
313 
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)314 void AttributesTogglerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
315 {
316 	QGraphicsItem *parent = this->parentItem();
317 	RoundedRectItem::paint(painter, option, widget);
318 
319 	for(unsigned arr_id = 0; arr_id < 7; arr_id++)
320 	{
321 		if(!buttons[arr_id]->isVisible())
322 			continue;
323 
324 		painter->save();
325 		painter->translate(buttons[arr_id]->pos());
326 		painter->setOpacity(buttons[arr_id]->opacity() * (parent ? parent->opacity() : 1));
327 		buttons[arr_id]->paint(painter, option, widget);
328 		painter->restore();
329 
330 		// Drawing the selection rectangle over the button if it isn't faded
331 		if(btns_selected[arr_id] && buttons[arr_id]->opacity() > ButtonMinOpacity)
332 		{
333 			painter->save();
334 			painter->translate(sel_rect->pos());
335 			sel_rect->paint(painter, option, widget);
336 			painter->restore();
337 		}
338 	}
339 }
340 
createButtonPolygons()341 void AttributesTogglerItem::createButtonPolygons()
342 {
343 	if(!btn_polygons[0].isEmpty())
344 		return;
345 
346 	QPolygonF *pol = nullptr;
347 	double fnt_factor = qApp->screens().at(qApp->desktop()->screenNumber(qApp->activeWindow()))->logicalDotsPerInch() / 96.0,
348 			pixel_ratio = qApp->screens().at(qApp->desktop()->screenNumber(qApp->activeWindow()))->devicePixelRatio(),
349 			factor = fnt_factor * pixel_ratio;
350 
351 	pol = &btn_polygons[PrevAttribsPageBtn];
352 	pol->append(QPointF(0, 5 * factor));
353 	pol->append(QPointF(8 * factor, 0));
354 	pol->append(QPointF(8 * factor, 10 * factor));
355 
356 	pol = &btn_polygons[NextAttribsPageBtn];
357 	pol->append(QPointF(0, 0));
358 	pol->append(QPointF(8 * factor, 5 * factor));
359 	pol->append(QPointF(0, 10 * factor));
360 
361 	pol = &btn_polygons[PrevExtAttribsPageBtn];
362 	pol->append(QPointF(0, 0));
363 	pol->append(QPointF(2 * factor, 0));
364 	pol->append(QPointF(2 * factor, 4 * factor));
365 	pol->append(QPointF(8 * factor, 0));
366 	pol->append(QPointF(8 * factor, 10 * factor));
367 	pol->append(QPointF(2 * factor, 6 * factor));
368 	pol->append(QPointF(2 * factor, 10 * factor));
369 	pol->append(QPointF(0, 10 * factor));
370 
371 	pol = &btn_polygons[NextExtAttribsPageBtn];
372 	pol->append(QPointF(0, 0));
373 	pol->append(QPointF(6 * factor, 4 * factor));
374 	pol->append(QPointF(6 * factor, 0 * factor));
375 	pol->append(QPointF(8 * factor, 0));
376 	pol->append(QPointF(8 * factor, 10 * factor));
377 	pol->append(QPointF(6 * factor, 10 * factor));
378 	pol->append(QPointF(6 * factor, 6 * factor));
379 	pol->append(QPointF(0, 10 * factor));
380 
381 	pol = &btn_polygons[AttribsCollapseBtn];
382 	pol->append(QPointF(5 * factor, 0));
383 	pol->append(QPointF(0, 8 * factor));
384 	pol->append(QPointF(10 * factor, 8 * factor));
385 
386 	pol = &btn_polygons[AttribsExpandBtn];
387 	pol->append(QPointF(0, 0));
388 	pol->append(QPointF(10 * factor, 0));
389 	pol->append(QPointF(5 * factor, 8 * factor));
390 
391 	pol = &btn_polygons[PaginationTogglerBtn];
392 	pol->append(QPointF(4 * factor, 0));
393 	pol->append(QPointF(8 * factor, 4 * factor));
394 	pol->append(QPointF(4 * factor, 8 * factor));
395 	pol->append(QPointF(0, 4 * factor));
396 }
397