1 /**
2  * @file
3  */
4 
5 /*
6 Copyright (C) 2002-2013 UFO: Alien Invasion.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
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
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22 
23 */
24 
25 #include "ui_internal.h"
26 #include "ui_dragndrop.h"
27 #include "ui_input.h"
28 #include "ui_node.h"
29 #include "ui_sound.h"
30 
31 #include "node/ui_node_abstractnode.h"
32 #include "node/ui_node_container.h"
33 
34 #include "../input/cl_input.h"
35 
36 static int oldMousePosX = -1;				/**< Save position X of the mouse to know when it move */
37 static int oldMousePosY = -1;				/**< Save position Y of the mouse to know when it move */
38 
39 static bool nodeAcceptDND = false;		/**< Save if the current target node can accept the DND object */
40 static bool positionAcceptDND = false;	/**< Save if the current position accept the DND object */
41 
42 static uiDNDType_t objectType;				/**< Save the type of the object we are dragging */
43 static Item draggingItem;					/**< Save the dragging object */
44 
45 static uiNode_t* sourceNode;				/**< Node where come from the DND object */
46 static uiNode_t* targetNode;				/**< Current node under the mouse */
47 
48 
49 /**
50  * @brief Return true if we are dragging something
51  */
UI_DNDIsDragging(void)52 bool UI_DNDIsDragging (void)
53 {
54 	return objectType != DND_NOTHING;
55 }
56 
57 /**
58  * @brief Return true if the requested node is the current target of the DND
59  */
UI_DNDIsTargetNode(uiNode_t * node)60 bool UI_DNDIsTargetNode (uiNode_t* node)
61 {
62 	if (!UI_DNDIsDragging())
63 		return false;
64 	return targetNode == node;
65 }
66 
67 /**
68  * @brief Return true if the requested node is the source of the DND
69  */
UI_DNDIsSourceNode(uiNode_t * node)70 bool UI_DNDIsSourceNode (uiNode_t* node)
71 {
72 	if (!UI_DNDIsDragging())
73 		return false;
74 	return sourceNode == node;
75 }
76 
77 /**
78  * @brief Return the current type of the dragging object, else DND_NOTHING
79  */
UI_DNDGetType(void)80 int UI_DNDGetType (void)
81 {
82 	return objectType;
83 }
84 
85 /**
86  * @brief Return target of the DND
87  */
UI_DNDGetTargetNode(void)88 uiNode_t* UI_DNDGetTargetNode (void)
89 {
90 	assert(UI_DNDIsDragging());
91 	return targetNode;
92 }
93 
94 /**
95  * @brief Return source of the DND
96  */
UI_DNDGetSourceNode(void)97 uiNode_t* UI_DNDGetSourceNode (void)
98 {
99 	assert(UI_DNDIsDragging());
100 	return sourceNode;
101 }
102 
103 /**
104  * @brief Private function to initialize a the start of a DND
105  * @sa UI_DNDDragItem
106  * @sa UI_DNDDrop
107  * @sa UI_DNDAbort
108  */
UI_DNDDrag(uiNode_t * node)109 static void UI_DNDDrag (uiNode_t* node)
110 {
111 	assert(!UI_DNDIsDragging());
112 	objectType = DND_SOMETHING;
113 	sourceNode = node;
114 
115 	UI_PlaySound("item-drag");
116 }
117 
118 /**
119  * @brief Start to drag an item
120  * @sa UI_DNDDrag
121  * @sa UI_DNDDrop
122  * @sa UI_DNDAbort
123  */
UI_DNDDragItem(uiNode_t * node,const Item * item)124 void UI_DNDDragItem (uiNode_t* node, const Item* item)
125 {
126 	UI_DNDDrag(node);
127 	assert(UI_DNDIsDragging());
128 	objectType = DND_ITEM;
129 	draggingItem = *item;
130 }
131 
132 /**
133  * @brief Cleanup data about DND
134  */
UI_DNDCleanup(void)135 static inline void UI_DNDCleanup (void)
136 {
137 	objectType = DND_NOTHING;
138 	targetNode = nullptr;
139 	sourceNode = nullptr;
140 }
141 
142 /**
143  * @brief Drop the object at the current position
144  * @sa UI_DNDStartDrag
145  * @sa UI_DNDDrop
146  */
UI_DNDAbort(void)147 void UI_DNDAbort (void)
148 {
149 	assert(UI_DNDIsDragging());
150 	assert(objectType != DND_NOTHING);
151 	assert(sourceNode != nullptr);
152 
153 	if (nodeAcceptDND && targetNode) {
154 		UI_Node_DndLeave(targetNode);
155 	}
156 	UI_Node_DndFinished(sourceNode, false);
157 
158 	UI_DNDCleanup();
159 	UI_InvalidateMouse();
160 }
161 
162 /**
163  * @brief Drop the object at the current position
164  * @sa UI_DNDStartDrag
165  * @sa UI_DNDAbort
166  */
UI_DNDDrop(void)167 void UI_DNDDrop (void)
168 {
169 	bool result = false;
170 	assert(UI_DNDIsDragging());
171 	assert(objectType != DND_NOTHING);
172 	assert(sourceNode != nullptr);
173 
174 	if (!positionAcceptDND) {
175 		UI_DNDAbort();
176 		return;
177 	}
178 
179 	if (targetNode) {
180 		result = UI_Node_DndDrop(targetNode, mousePosX, mousePosY);
181 	}
182 	UI_Node_DndFinished(sourceNode, result);
183 
184 	UI_PlaySound("item-drop");
185 
186 	UI_DNDCleanup();
187 	UI_InvalidateMouse();
188 }
189 
UI_DNDGetItem(void)190 Item* UI_DNDGetItem (void)
191 {
192 	assert(objectType == DND_ITEM);
193 	return &draggingItem;
194 }
195 
196 /**
197  * @brief Manage the DND when we move the mouse
198  */
UI_DNDMouseMove(int mousePosX,int mousePosY)199 static void UI_DNDMouseMove (int mousePosX, int mousePosY)
200 {
201 	uiNode_t* node = UI_GetNodeAtPosition(mousePosX, mousePosY);
202 
203 	if (node != targetNode) {
204 		if (nodeAcceptDND && targetNode) {
205 			UI_Node_DndLeave(targetNode);
206 		}
207 		targetNode = node;
208 		if (targetNode) {
209 			nodeAcceptDND = UI_Node_DndEnter(targetNode);
210 		}
211 	}
212 
213 	if (targetNode == nullptr) {
214 		nodeAcceptDND = false;
215 		positionAcceptDND = false;
216 		return;
217 	}
218 
219 	if (!nodeAcceptDND) {
220 		positionAcceptDND = false;
221 		return;
222 	}
223 
224 	positionAcceptDND = UI_Node_DndMove(targetNode, mousePosX, mousePosY);
225 }
226 
227 /**
228  * @brief Draw to dragging object and catch mouse move event
229  */
UI_DrawDragAndDrop(int mousePosX,int mousePosY)230 void UI_DrawDragAndDrop (int mousePosX, int mousePosY)
231 {
232 	const vec3_t scale = { 3.5, 3.5, 3.5 };
233 	vec3_t orgine;
234 	vec4_t color = { 1, 1, 1, 1 };
235 
236 	/* check mouse move */
237 	if (mousePosX != oldMousePosX || mousePosY != oldMousePosY) {
238 		oldMousePosX = mousePosX;
239 		oldMousePosY = mousePosY;
240 		UI_DNDMouseMove(mousePosX, mousePosY);
241 	}
242 
243 	/* draw the dragging item */
244 
245 	VectorSet(orgine, mousePosX, mousePosY, -50);
246 
247 	/* Tune down the opacity of the cursor-item if the preview item is drawn. */
248 	if (positionAcceptDND)
249 		color[3] = 0.2;
250 
251 	switch (objectType) {
252 	case DND_ITEM:
253 		UI_DrawItem(nullptr, orgine, &draggingItem, -1, -1, scale, color);
254 		break;
255 
256 	default:
257 		assert(false);
258 	}
259 }
260