/** * @brief Main function to draw a container node */ void uiContainerNode::draw (uiNode_t *node) { const objDef_t *highlightType = NULL; if (!EXTRADATA(node).container) return; if (!ui_inventory) return; /* is container invisible */ if (node->color[3] < 0.001) return; /* Highlight weapons that the dragged ammo (if it is one) can be loaded into. */ if (UI_DNDIsDragging() && UI_DNDGetType() == DND_ITEM) { highlightType = UI_DNDGetItem()->item; } if (EXTRADATA(node).container->single) { UI_ContainerNodeDrawSingle(node, highlightType); } else { if (UI_IsScrollContainerNode(node)) { assert(false); } else { UI_ContainerNodeDrawGrid(node, highlightType); } } /* Draw free space if dragging - but not for idEquip */ if (UI_DNDIsDragging() && EXTRADATA(node).container->id != csi.idEquip) UI_ContainerNodeDrawFreeSpace(node, ui_inventory); if (UI_DNDIsTargetNode(node)) UI_ContainerNodeDrawDropPreview(node); }
/** * @brief Called by the client when the user type a key * @param[in] key key code, either K_ value or lowercase ascii * @param[in] unicode translated meaning of keypress in unicode * @return true, if we used the event * @todo think about what we should do when the mouse is captured */ bool UI_KeyPressed (unsigned int key, unsigned short unicode) { int windowId; int lastWindowId; if (UI_DNDIsDragging()) { if (key == K_ESCAPE) UI_DNDAbort(); return false; } if (key == K_ESCAPE && CL_BattlescapeRunning() && selActor && CL_ActorFireModeActivated(selActor->actorMode)) { /* Cancel firing with Escape, needed for Android, where right mouse click is bound to multitouch, which is non-obvious */ CL_ActorSetMode(selActor, M_MOVE); return true; } /* translate event into the node with focus */ if (focusNode && UI_Node_KeyPressed(focusNode, key, unicode)) { return true; } /* else use common behaviour */ switch (key) { case K_TAB: if (UI_FocusNextActionNode()) return true; break; case K_ENTER: case K_KP_ENTER: if (UI_FocusExecuteActionNode()) return true; break; case K_ESCAPE: if (UI_GetMouseCapture() != nullptr) { UI_MouseRelease(); return true; } UI_PopWindowWithEscKey(); return true; } lastWindowId = UI_GetLastFullScreenWindow(); if (lastWindowId < 0) return false; /* check "active" window from top to down */ for (windowId = ui_global.windowStackPos - 1; windowId >= lastWindowId; windowId--) { const uiNode_t* window = ui_global.windowStack[windowId]; if (!window) return false; if (UI_KeyPressedInWindow(key, window)) return true; if (UI_WindowIsModal(window)) break; } return false; }
/** * @brief Start to drag an item * @sa UI_DNDDrag * @sa UI_DNDDrop * @sa UI_DNDAbort */ void UI_DNDDragItem (uiNode_t* node, const Item* item) { UI_DNDDrag(node); assert(UI_DNDIsDragging()); objectType = DND_ITEM; draggingItem = *item; }
void uiContainerNode::onMouseDown (uiNode_t *node, int x, int y, int button) { switch (button) { case K_MOUSE1: { /* start drag and drop */ int fromX, fromY; dragInfoIC = UI_ContainerNodeGetItemAtPosition(node, x, y, &fromX, &fromY); if (dragInfoIC) { dragInfoFromX = fromX; dragInfoFromY = fromY; oldMouseX = x; oldMouseY = y; UI_SetMouseCapture(node); EXTRADATA(node).lastSelectedId = dragInfoIC->item.item->idx; if (EXTRADATA(node).onSelect) { UI_ExecuteEventActions(node, EXTRADATA(node).onSelect); } } break; } case K_MOUSE2: if (UI_DNDIsDragging()) { UI_DNDAbort(); } else { /* auto place */ UI_ContainerNodeAutoPlace(node, x, y); } break; default: break; } }
/** * @brief Release all captured input (keyboard or mouse) */ void UI_ReleaseInput (void) { UI_RemoveFocus(); UI_MouseRelease(); if (UI_DNDIsDragging()) UI_DNDAbort(); }
/** * @brief Private function to initialize a the start of a DND * @sa UI_DNDDragItem * @sa UI_DNDDrop * @sa UI_DNDAbort */ static void UI_DNDDrag (uiNode_t* node) { assert(!UI_DNDIsDragging()); objectType = DND_SOMETHING; sourceNode = node; UI_PlaySound("item-drag"); }
void uiBaseInventoryNode::onMouseUp (uiNode_t* node, int x, int y, int button) { if (button != K_MOUSE1) return; if (UI_GetMouseCapture() == node) { UI_MouseRelease(); } if (UI_DNDIsDragging()) { UI_DNDDrop(); } }
/** * @brief Called by the client when the user type a key * @param[in] key key code, either K_ value or lowercase ascii * @param[in] unicode translated meaning of keypress in unicode * @return true, if we used the event * @todo think about what we should do when the mouse is captured */ bool UI_KeyPressed (unsigned int key, unsigned short unicode) { int windowId; int lastWindowId; if (UI_DNDIsDragging()) { if (key == K_ESCAPE) UI_DNDAbort(); return false; } /* translate event into the node with focus */ if (focusNode && UI_Node_KeyPressed(focusNode, key, unicode)) { return true; } /* else use common behaviour */ switch (key) { case K_TAB: if (UI_FocusNextActionNode()) return true; break; case K_ENTER: case K_KP_ENTER: if (UI_FocusExecuteActionNode()) return true; break; case K_ESCAPE: if (UI_GetMouseCapture() != NULL) { UI_MouseRelease(); return true; } UI_PopWindowWithEscKey(); return true; } lastWindowId = UI_GetLastFullScreenWindow(); if (lastWindowId < 0) return false; /* check "active" window from top to down */ for (windowId = ui_global.windowStackPos - 1; windowId >= lastWindowId; windowId--) { const uiNode_t *window = ui_global.windowStack[windowId]; if (!window) return false; if (UI_KeyPressedInWindow(key, window)) return true; if (UI_WindowIsModal(window)) break; } return false; }
/** * @brief Drop the object at the current position * @sa UI_DNDStartDrag * @sa UI_DNDDrop */ void UI_DNDAbort (void) { assert(UI_DNDIsDragging()); assert(objectType != DND_NOTHING); assert(sourceNode != nullptr); if (nodeAcceptDND && targetNode) { UI_Node_DndLeave(targetNode); } UI_Node_DndFinished(sourceNode, false); UI_DNDCleanup(); UI_InvalidateMouse(); }
/** * @brief Draws the free and usable inventory positions when dragging an item. * @note Only call this function in dragging mode */ static void UI_ContainerNodeDrawFreeSpace (uiNode_t *node, inventory_t *inv) { const objDef_t *od = UI_DNDGetItem()->item; /**< Get the 'type' of the dragged item. */ vec2_t nodepos; /* Draw only in dragging-mode and not for the equip-floor */ assert(UI_DNDIsDragging()); assert(inv); UI_GetNodeAbsPos(node, nodepos); /* if single container (hands, extension, headgear) */ if (EXTRADATA(node).container->single) { /* if container is free or the dragged-item is in it */ if (UI_DNDIsSourceNode(node) || INVSH_CheckToInventory(inv, od, EXTRADATA(node).container, 0, 0, dragInfoIC)) UI_DrawFree(EXTRADATA(node).container->id, node, nodepos[0], nodepos[1], node->box.size[0], node->box.size[1], true); } else { /* The shape of the free positions. */ uint32_t free[SHAPE_BIG_MAX_HEIGHT]; bool showTUs = true; int x, y; OBJZERO(free); for (y = 0; y < SHAPE_BIG_MAX_HEIGHT; y++) { for (x = 0; x < SHAPE_BIG_MAX_WIDTH; x++) { /* Check if the current position is usable (topleft of the item). */ /* Add '1's to each position the item is 'blocking'. */ const int checkedTo = INVSH_CheckToInventory(inv, od, EXTRADATA(node).container, x, y, dragInfoIC); if (checkedTo & INV_FITS) /* Item can be placed normally. */ INVSH_MergeShapes(free, (uint32_t)od->shape, x, y); if (checkedTo & INV_FITS_ONLY_ROTATED) /* Item can be placed rotated. */ INVSH_MergeShapes(free, INVSH_ShapeRotate((uint32_t)od->shape), x, y); /* Only draw on existing positions. */ if (INVSH_CheckShape(EXTRADATA(node).container->shape, x, y)) { if (INVSH_CheckShape(free, x, y)) { UI_DrawFree(EXTRADATA(node).container->id, node, nodepos[0] + x * C_UNIT, nodepos[1] + y * C_UNIT, C_UNIT, C_UNIT, showTUs); showTUs = false; } } } } } }
/** * @brief Main function to draw a container node */ void uiBaseInventoryNode::draw (uiNode_t* node) { const objDef_t* highlightType = nullptr; if (!EXTRADATA(node).super.container) return; if (!ui_inventory) return; /* is container invisible */ if (node->color[3] < 0.001) return; /* Highlight weapons that the dragged ammo (if it is one) can be loaded into. */ if (UI_DNDIsDragging() && UI_DNDGetType() == DND_ITEM) { highlightType = UI_DNDGetItem()->def(); } UI_BaseInventoryNodeDraw2(node, highlightType); }
/** * @brief Drop the object at the current position * @sa UI_DNDStartDrag * @sa UI_DNDAbort */ void UI_DNDDrop (void) { bool result = false; assert(UI_DNDIsDragging()); assert(objectType != DND_NOTHING); assert(sourceNode != nullptr); if (!positionAcceptDND) { UI_DNDAbort(); return; } if (targetNode) { result = UI_Node_DndDrop(targetNode, mousePosX, mousePosY); } UI_Node_DndFinished(sourceNode, result); UI_PlaySound("item-drop"); UI_DNDCleanup(); UI_InvalidateMouse(); }
/** * @brief Draws the 3D-cursor in battlemode and the icons/info next to it. */ static void SCR_DrawCursor (void) { if (scr_showcursor->integer == 0) return; if (!scr_cursor->integer) return; if (scr_cursor->modified) { scr_cursor->modified = qfalse; SCR_TouchPics(); } if (!cursorImage[0]) return; if (!UI_DNDIsDragging()) { const char *pic; image_t *image; if (cls.team != cl.actTeam && CL_BattlescapeRunning()) pic = "pics/cursors/wait"; else pic = cursorImage; image = R_FindImage(pic, it_pic); if (image) R_DrawImage(mousePosX - image->width / 2, mousePosY - image->height / 2, image); if (IN_GetMouseSpace() == MS_WORLD && CL_BattlescapeRunning()) { HUD_UpdateCursor(); } } else { UI_DrawCursor(); } }
/** * @brief Return source of the DND */ uiNode_t* UI_DNDGetSourceNode (void) { assert(UI_DNDIsDragging()); return sourceNode; }
/** * @brief Return target of the DND */ uiNode_t* UI_DNDGetTargetNode (void) { assert(UI_DNDIsDragging()); return targetNode; }
/** * @brief Return true if the requested node is the source of the DND */ bool UI_DNDIsSourceNode (uiNode_t* node) { if (!UI_DNDIsDragging()) return false; return sourceNode == node; }
/** * @brief Return true if the requested node is the current target of the DND */ bool UI_DNDIsTargetNode (uiNode_t* node) { if (!UI_DNDIsDragging()) return false; return targetNode == node; }
/** * @brief Is called every time the mouse position change */ void UI_MouseMove (int x, int y) { if (UI_DNDIsDragging()) return; if (pressedNode && !capturedNode) { if (pressedNodeLocationX != UI_STARTDRAG_ALREADY_SENT) { UI_TimerStop(longPressTimer); int dist = abs(pressedNodeLocationX - x) + abs(pressedNodeLocationY - y); if (dist > 4) { uiNode_t* node = pressedNode; while (node) { if (UI_Node_StartDragging(node, pressedNodeLocationX, pressedNodeLocationY, x, y, pressedNodeButton)) break; node = node->parent; } pressedNodeLocationX = UI_STARTDRAG_ALREADY_SENT; } } } /* send the captured move mouse event */ if (capturedNode) { UI_Node_CapturedMouseMove(capturedNode, x, y); return; } hoveredNode = UI_GetNodeAtPosition(x, y); /* update houvered node by sending messages */ if (oldHoveredNode != hoveredNode) { uiNode_t* commonNode = hoveredNode; uiNode_t* node; /* search the common node */ while (commonNode) { node = oldHoveredNode; while (node) { if (node == commonNode) break; node = node->parent; } if (node != nullptr) break; commonNode = commonNode->parent; } /* send 'leave' event from old node to common node */ node = oldHoveredNode; while (node != commonNode) { UI_Node_MouseLeave(node); node = node->parent; } if (oldHoveredNode) oldHoveredNode->state = false; /* send 'enter' event from common node to new node */ while (commonNode != hoveredNode) { /** @todo we can remove that loop with an array allocation */ node = hoveredNode; while (node->parent != commonNode) node = node->parent; commonNode = node; UI_Node_MouseEnter(node); } if (hoveredNode) { hoveredNode->state = true; UI_Node_MouseEnter(node); } } oldHoveredNode = hoveredNode; /* send the move event */ if (hoveredNode) UI_Node_MouseMove(hoveredNode, x, y); }