1 /*
2 Copyright © 2018 Justin Jacobs
3 
4 This file is part of FLARE.
5 
6 FLARE is free software: you can redistribute it and/or modify it under the terms
7 of the GNU General Public License as published by the Free Software Foundation,
8 either version 3 of the License, or (at your option) any later version.
9 
10 FLARE is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
12 PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along with
15 FLARE.  If not, see http://www.gnu.org/licenses/
16 */
17 
18 /**
19  * class WidgetHorizontalList
20  */
21 
22 #include "EngineSettings.h"
23 #include "FontEngine.h"
24 #include "InputState.h"
25 #include "RenderDevice.h"
26 #include "SharedResources.h"
27 #include "TooltipManager.h"
28 #include "WidgetButton.h"
29 #include "WidgetHorizontalList.h"
30 
31 const std::string WidgetHorizontalList::DEFAULT_FILE_LEFT = "images/menus/buttons/left.png";
32 const std::string WidgetHorizontalList::DEFAULT_FILE_RIGHT = "images/menus/buttons/right.png";
33 
WidgetHorizontalList()34 WidgetHorizontalList::WidgetHorizontalList()
35 	: Widget()
36 	, button_left(new WidgetButton(DEFAULT_FILE_LEFT))
37 	, button_right(new WidgetButton(DEFAULT_FILE_RIGHT))
38 	, cursor(0)
39 	, changed_without_mouse(false)
40 	, enabled(true)
41 {
42 	focusable = true;
43 	scroll_type = SCROLL_HORIZONTAL;
44 	refresh();
45 }
46 
47 // void WidgetHorizontalList::activate() {
48 // }
49 
setPos(int offset_x,int offset_y)50 void WidgetHorizontalList::setPos(int offset_x, int offset_y) {
51 	Widget::setPos(offset_x, offset_y);
52 	refresh();
53 }
54 
checkClick()55 bool WidgetHorizontalList::checkClick() {
56 	return checkClickAt(inpt->mouse.x,inpt->mouse.y);
57 }
58 
checkClickAt(int x,int y)59 bool WidgetHorizontalList::checkClickAt(int x, int y) {
60 	// enable_tablist_nav = enabled;
61 
62 	Point mouse(x,y);
63 
64 	checkTooltip(mouse);
65 
66 	if (button_left->checkClickAt(mouse.x, mouse.y)) {
67 		scrollLeft();
68 		return true;
69 	}
70 	else if (button_right->checkClickAt(mouse.x, mouse.y)) {
71 		scrollRight();
72 		return true;
73 	}
74 	else if (changed_without_mouse) {
75 		// getNext() or getPrev() was used to change the slider, so treat it as a "click"
76 		changed_without_mouse = false;
77 		return true;
78 	}
79 
80 
81 	return false;
82 }
83 
render()84 void WidgetHorizontalList::render() {
85 	button_left->local_frame = local_frame;
86 	button_left->local_offset = local_offset;
87 
88 	button_right->local_frame = local_frame;
89 	button_right->local_offset = local_offset;
90 
91 	button_left->render();
92 	button_right->render();
93 
94 	// render label
95 	label.local_frame = local_frame;
96 	label.local_offset = local_offset;
97 	label.render();
98 
99 	if (in_focus) {
100 		Point topLeft;
101 		Point bottomRight;
102 
103 		topLeft.x = pos.x + local_frame.x - local_offset.x;
104 		topLeft.y = pos.y + local_frame.y - local_offset.y;
105 		bottomRight.x = topLeft.x + pos.w;
106 		bottomRight.y = topLeft.y + pos.h;
107 
108 		// Only draw rectangle if it fits in local frame
109 		bool draw = true;
110 		if (local_frame.w &&
111 				(topLeft.x<local_frame.x || bottomRight.x>(local_frame.x+local_frame.w))) {
112 			draw = false;
113 		}
114 		if (local_frame.h &&
115 				(topLeft.y<local_frame.y || bottomRight.y>(local_frame.y+local_frame.h))) {
116 			draw = false;
117 		}
118 		if (draw || 1) {
119 			render_device->drawRectangle(topLeft, bottomRight, eset->widgets.selection_rect_color);
120 		}
121 	}
122 }
123 
refresh()124 void WidgetHorizontalList::refresh() {
125 	const int text_width = eset->widgets.horizontal_list_text_width;
126 	bool is_enabled = !isEmpty() && enabled;
127 
128 	label.setText(getValue());
129 	label.setPos(pos.x + button_left->pos.w + text_width/2, pos.y + button_left->pos.h / 2);
130 	label.setMaxWidth(text_width);
131 	label.setJustify(FontEngine::JUSTIFY_CENTER);
132 	label.setVAlign(LabelInfo::VALIGN_CENTER);
133 	label.setColor(is_enabled ? font->getColor(FontEngine::COLOR_WIDGET_NORMAL) : font->getColor(FontEngine::COLOR_WIDGET_DISABLED));
134 
135 	button_left->setPos(pos.x, pos.y);
136 	button_right->setPos(pos.x + button_left->pos.w + text_width, pos.y);
137 
138 	button_left->enabled = is_enabled;
139 	button_right->enabled = is_enabled;
140 
141 	pos.w = button_left->pos.w + button_right->pos.w + text_width;
142 	pos.h = std::max(button_left->pos.h, label.getBounds()->h);
143 
144 	tooltip_area.x = pos.x + button_left->pos.w;
145 	tooltip_area.y = std::min(pos.y, label.getBounds()->y);
146 	tooltip_area.w = text_width;
147 	tooltip_area.h = std::max(button_left->pos.h, label.getBounds()->h);
148 }
149 
checkTooltip(const Point & mouse)150 void WidgetHorizontalList::checkTooltip(const Point& mouse) {
151 	if (isEmpty())
152 		return;
153 
154 	if (inpt->usingMouse() && Utils::isWithinRect(tooltip_area, mouse) && !list_items[cursor].tooltip.empty()) {
155 		TooltipData tip_data;
156 		tip_data.addText(list_items[cursor].tooltip);
157 		Point new_mouse(mouse.x + local_frame.x - local_offset.x, mouse.y + local_frame.y - local_offset.y);
158 		tooltipm->push(tip_data, new_mouse, TooltipData::STYLE_FLOAT);
159 	}
160 }
161 
append(const std::string & value,const std::string & tooltip)162 void WidgetHorizontalList::append(const std::string& value, const std::string& tooltip) {
163 	HListItem hli;
164 	hli.value = value;
165 	hli.tooltip = tooltip;
166 
167 	list_items.push_back(hli);
168 }
169 
clear()170 void WidgetHorizontalList::clear() {
171 	list_items.clear();
172 }
173 
getValue()174 std::string WidgetHorizontalList::getValue() {
175 	if (cursor < getSize()) {
176 		return list_items[cursor].value;
177 	}
178 
179 	return "";
180 }
181 
getSelected()182 unsigned WidgetHorizontalList::getSelected() {
183 	if (cursor < getSize())
184 		return cursor;
185 	else
186 		return getSize();
187 }
188 
getSize()189 unsigned WidgetHorizontalList::getSize() {
190 	return static_cast<unsigned>(list_items.size());
191 }
192 
isEmpty()193 bool WidgetHorizontalList::isEmpty() {
194 	return list_items.empty();
195 }
196 
scrollLeft()197 void WidgetHorizontalList::scrollLeft() {
198 	if (isEmpty())
199 		return;
200 
201 	if (cursor == 0)
202 		cursor = getSize() - 1;
203 	else
204 		cursor--;
205 
206 	refresh();
207 }
208 
select(unsigned index)209 void WidgetHorizontalList::select(unsigned index) {
210 	if (isEmpty())
211 		return;
212 
213 	if (index < getSize())
214 		cursor = index;
215 
216 	refresh();
217 }
218 
scrollRight()219 void WidgetHorizontalList::scrollRight() {
220 	if (isEmpty())
221 		return;
222 
223 	if (cursor+1 >= getSize())
224 		cursor = 0;
225 	else
226 		cursor++;
227 
228 	refresh();
229 }
230 
getPrev()231 bool WidgetHorizontalList::getPrev() {
232 	if (!isEmpty() && enabled) {
233 		scrollLeft();
234 		changed_without_mouse = true;
235 	}
236 	return true;
237 }
238 
getNext()239 bool WidgetHorizontalList::getNext() {
240 	if (!isEmpty() && enabled) {
241 		scrollRight();
242 		changed_without_mouse = true;
243 	}
244 	return true;
245 }
246 
~WidgetHorizontalList()247 WidgetHorizontalList::~WidgetHorizontalList() {
248 	delete button_left;
249 	delete button_right;
250 }
251 
252