guihandler.cpp

来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 2,423 行 · 第 1/5 页

CPP
2,423
字号
	if (!game->hideInterface) {
		ir = GetReceiverAt(mouse->lastx, mouse->lasty);
	}

	if ((ir != NULL) && (ir != minimap)) {
		return;
	}

	if (ir == minimap) {
		mouse->cursorScale = minimap->CursorScale();
	}

	const bool useMinimap =
		(minimap->ProxyMode() || ((activeReceiver != this) && (ir == minimap)));

	if ((inCommand >= 0) && (inCommand<commands.size())) {
		const CommandDescription& cmdDesc = commands[inCommand];

		if (!cmdDesc.mouseicon.empty()) {
			mouse->cursorText = cmdDesc.mouseicon;
		} else {
			mouse->cursorText = cmdDesc.name;
		}

		if (useMinimap && (cmdDesc.id < 0)) {
			BuildInfo bi;
			bi.pos = minimap->GetMapPosition(mouse->lastx, mouse->lasty);
			bi.buildFacing = bi.buildFacing;
			bi.def = unitDefHandler->GetUnitByID(-cmdDesc.id);
			bi.pos = helper->Pos2BuildPos(bi);
			// if an unit (enemy), is not in LOS, then TestUnitBuildSquare()
			// does not consider it when checking for position blocking
			CFeature* feature;
			if(!uh->TestUnitBuildSquare(bi, feature, gu->myAllyTeam)) {
				mouse->cursorText = "BuildBad";
			} else {
				mouse->cursorText = "BuildGood";
			}
		}
	}
	else if (!useMinimap || minimap->FullProxy()) {
		int defcmd;
		if (mouse->buttons[SDL_BUTTON_RIGHT].pressed &&
				((activeReceiver == this) || (minimap->ProxyMode()))) {
			defcmd = defaultCmdMemory;
		} else {
			defcmd = GetDefaultCommand(mouse->lastx, mouse->lasty);
		}
		if ((defcmd >= 0) && (defcmd < commands.size())) {
			const CommandDescription& cmdDesc = commands[defcmd];
			if (!cmdDesc.mouseicon.empty()) {
				mouse->cursorText = cmdDesc.mouseicon;
			} else {
				mouse->cursorText = cmdDesc.name;
			}
		}
	}

	if (gatherMode && (mouse->cursorText == "Move")) {
		mouse->cursorText = "GatherWait";
	}
}


bool CGuiHandler::MousePress(int x, int y, int button)
{
	if (luaUI != NULL) {
		luaUIClick = luaUI->MousePress(x, y, button);
		if (luaUIClick) {
			return true;
		}
	}

	if (button == SDL_BUTTON_MIDDLE) {
		return false;
	}

	if (button < 0) {
		// proxied click from the minimap
		button = -button;
		activeMousePress=true;
	}
	else if (AboveGui(x,y)) {
		activeMousePress = true;
		return true;
	}
	else if (minimap && minimap->IsAbove(x, y)) {
		return false; // let the minimap do its job
	}

	if (inCommand >= 0) {
		if (invertQueueKey && (button == SDL_BUTTON_RIGHT) &&
		    !mouse->buttons[SDL_BUTTON_LEFT].pressed) { // for rocker gestures
			SetShowingMetal(false);
			inCommand = -1;
			needShift = false;
			return false;
		}
		activeMousePress = true;
		return true;
	}

	if (button == SDL_BUTTON_RIGHT) {
		activeMousePress = true;
		defaultCmdMemory = GetDefaultCommand(x, y);
		return true;
	}

	return false;
}


void CGuiHandler::MouseMove(int x, int y, int dx, int dy, int button)
{
	if (luaUI != NULL) {
		luaUI->MouseMove(x, y, dx, dy, button);
	}
}


void CGuiHandler::MouseRelease(int x, int y, int button)
{
	int iconCmd = -1;

	if (luaUIClick) {
		luaUIClick = false;
		if (luaUI != NULL) {
			iconCmd = luaUI->MouseRelease(x, y, button);
		}
		if ((iconCmd < 0) || (iconCmd >= commands.size())) {
			return;
		} else {
			activeMousePress = true;
		}
	}

	if (activeMousePress) {
		activeMousePress=false;
	} else {
		return;
	}

	if (!invertQueueKey && needShift && !keys[SDLK_LSHIFT]) {
		SetShowingMetal(false);
		inCommand=-1;
		needShift=false;
	}

	if (button < 0) {
		button = -button; // proxied click from the minimap
	} else {
		// setup iconCmd
		if ((iconCmd < 0) && !game->hideInterface) {
			const int iconPos = IconAtPos(x, y);
			if (iconPos >= 0) {
				iconCmd = icons[iconPos].commandsID;
			}
		}
	}

	if ((button == SDL_BUTTON_RIGHT) && (iconCmd == -1)) {
		// right click -> set the default cmd
		inCommand = defaultCmdMemory;
		defaultCmdMemory = -1;
	}

	if ((iconCmd >= 0) && (iconCmd < commands.size())) {
		const bool rmb = (button == SDL_BUTTON_LEFT) ? false : true;
		SetActiveCommand(iconCmd, rmb);
		return;
	}

	// not over a button, try to execute a command
	Command c = GetCommand(x, y, button, false);

	// if cmd_stop is returned it indicates that no good command could be found
	if (c.id != CMD_STOP) {
		GiveCommand(c);
		lastKeySet.Reset();
	}

	FinishCommand(button);
}


bool CGuiHandler::SetActiveCommand(int cmdIndex, bool rmb)
{
	if (cmdIndex >= (int)commands.size()) {
		return false;
	}
	else if (cmdIndex < 0) {
		// cancel the current command
		inCommand = -1;
		defaultCmdMemory = -1;
		needShift = false;
		activeMousePress = false;
		SetShowingMetal(false);
		return true;
	}

	CommandDescription& cd = commands[cmdIndex];
	if (cd.disabled) {
		return false;
	}

	lastKeySet.Reset();

	switch (cd.type) {
		case CMDTYPE_ICON: {
			Command c;
			c.id = cd.id;
			if (c.id != CMD_STOP) {
				CreateOptions(c, rmb);
				if (invertQueueKey && ((c.id < 0) || (c.id == CMD_STOCKPILE))) {
					c.options = c.options ^ SHIFT_KEY;
				}
			}
			GiveCommand(c);
			break;
		}
		case CMDTYPE_ICON_MODE: {
			int newMode = atoi(cd.params[0].c_str()) + 1;
			if (newMode > cd.params.size()-2) {
				newMode = 0;
			}

			// not really required
			char t[10];
			SNPRINTF(t, 10, "%d", newMode);
			cd.params[0] = t;

			Command c;
			c.id = cd.id;
			c.params.push_back(newMode);
			CreateOptions(c, rmb);
			GiveCommand(c);
			forceLayoutUpdate = true;
			break;
		}
		case CMDTYPE_NUMBER:
		case CMDTYPE_ICON_MAP:
		case CMDTYPE_ICON_AREA:
		case CMDTYPE_ICON_UNIT:
		case CMDTYPE_ICON_UNIT_OR_MAP:
		case CMDTYPE_ICON_FRONT:
		case CMDTYPE_ICON_UNIT_OR_AREA:
		case CMDTYPE_ICON_UNIT_OR_RECTANGLE:
		case CMDTYPE_ICON_UNIT_FEATURE_OR_AREA: {
			inCommand = cmdIndex;
			SetShowingMetal(false);
			activeMousePress = false;
			break;
		}
		case CMDTYPE_ICON_BUILDING: {
			const UnitDef* ud = unitDefHandler->GetUnitByID(-cd.id);
			inCommand = cmdIndex;
			SetShowingMetal(ud->extractsMetal > 0);
			activeMousePress = false;
			break;
		}
		case CMDTYPE_COMBO_BOX: {
			if (GetInputReceivers().empty() ||
			    dynamic_cast<CglList*>(GetInputReceivers().front()) == NULL) {
				inCommand = cmdIndex;
				SetShowingMetal(false);
				list = SAFE_NEW CglList(cd.name.c_str(), MenuSelection);
				list->cancelPlace = 0;
				list->tooltip =
					"Choose the AI you want to assign to this group.\n"
					"Select \"None\" to cancel or \"default\" to create a group without an AI\n"
					"assigned.";
				vector<string>::const_iterator pi;
				for (pi = ++cd.params.begin(); pi != cd.params.end(); ++pi) {
					list->AddItem(pi->c_str(),"");
				}
				list->place=atoi(cd.params[0].c_str());
			} else {
				inCommand = -1;
				SetShowingMetal(false);
			}
			activeMousePress = false;
			break;
		}
		case CMDTYPE_NEXT: {
			++activePage;
			if (activePage > maxPage) {
				activePage = 0;
			}
			selectedUnits.SetCommandPage(activePage);
			break;
		}
		case CMDTYPE_PREV: {
			--activePage;
			if (activePage < 0) {
				activePage=maxPage;
			}
			selectedUnits.SetCommandPage(activePage);
			break;
		}
		case CMDTYPE_CUSTOM: {
			RunCustomCommands(cd.params, rmb);
			break;
		}
		default:
			break;
	}

	return true;
}


bool CGuiHandler::SetActiveCommand(int cmdIndex, int button,
                                   bool lmb, bool rmb,
                                   bool alt, bool ctrl, bool meta, bool shift)
{
	// use the button value instead of rmb
	const bool effectiveRMB = (button == SDL_BUTTON_LEFT) ? false : true;

	// setup the mouse and key states
	const bool  prevLMB   = mouse->buttons[SDL_BUTTON_LEFT].pressed;
	const bool  prevRMB   = mouse->buttons[SDL_BUTTON_RIGHT].pressed;
	const Uint8 prevAlt   = keys[SDLK_LALT];
	const Uint8 prevCtrl  = keys[SDLK_LCTRL];
	const Uint8 prevMeta  = keys[SDLK_LMETA];
	const Uint8 prevShift = keys[SDLK_LSHIFT];

	mouse->buttons[SDL_BUTTON_LEFT].pressed  = lmb;
	mouse->buttons[SDL_BUTTON_RIGHT].pressed = rmb;
	keys[SDLK_LALT]   = alt;
	keys[SDLK_LCTRL]  = ctrl;
	keys[SDLK_LMETA]  = meta;
	keys[SDLK_LSHIFT] = shift;

	const bool retval = SetActiveCommand(cmdIndex, effectiveRMB);

	// revert the mouse and key states
	keys[SDLK_LSHIFT] = prevShift;
	keys[SDLK_LMETA]  = prevMeta;
	keys[SDLK_LCTRL]  = prevCtrl;
	keys[SDLK_LALT]   = prevAlt;
	mouse->buttons[SDL_BUTTON_RIGHT].pressed = prevRMB;
	mouse->buttons[SDL_BUTTON_LEFT].pressed  = prevLMB;

	return retval;
}


int CGuiHandler::IconAtPos(int x, int y)
{
	const float fx = MouseX(x);
	const float fy = MouseY(y);

	if ((fx < buttonBox.x1) || (fx > buttonBox.x2) ||
	    (fy < buttonBox.y1) || (fy > buttonBox.y2)) {
		return -1;
	}

	int xSlot = int((fx - (buttonBox.x1 + frameBorder)) / xIconStep);
	int ySlot = int(((buttonBox.y2 - frameBorder) - fy) / yIconStep);
	xSlot = min(max(xSlot, 0), xIcons - 1);
	ySlot = min(max(ySlot, 0), yIcons - 1);
  const int ii = (activePage * iconsPerPage) + (ySlot * xIcons) + xSlot;
  if ((ii >= 0) && (ii < iconsCount)) {
		if ((fx > icons[ii].selection.x1) && (fx < icons[ii].selection.x2) &&
				(fy > icons[ii].selection.y2) && (fy < icons[ii].selection.y1)) {
			return ii;
		}
	}

	return -1;
}


/******************************************************************************/

enum ModState {
	DontCare, Required, Forbidden
};

struct ModGroup {
	ModGroup()
	: alt(DontCare),
	  ctrl(DontCare),
	  meta(DontCare),
	  shift(DontCare),
	  right(DontCare) {}
	ModState alt, ctrl, meta, shift, right;
};


static bool ParseCustomCmdMods(string& cmd, ModGroup& in, ModGroup& out)
{
	const char* c = cmd.c_str();
	if (*c != '@') {
		return false;
	}
	c++;
	bool neg = false;
	while ((*c != 0) && (*c != '@')) {
		char ch = *c;
		if (ch == '-') {
			neg = true;
		}
		else if (ch == '+') {
			neg = false;
		}
		else if (ch == 'a') { in.alt    = neg ? Forbidden : Required; neg = false; }
		else if (ch == 'c') { in.ctrl   = neg ? Forbidden : Required; neg = false; }
		else if (ch == 'm') { in.meta   = neg ? Forbidden : Required; neg = false; }
		else if (ch == 's') { in.shift  = neg ? Forbidden : Required; neg = false; }
		else if (ch == 'r') { in.right  = neg ? Forbidden : Required; neg = false; }
		else if (ch == 'A') { out.alt   = neg ? Forbidden : Required; neg = false; }
		else if (ch == 'C') { out.ctrl  = neg ? Forbidden : Required; neg = false; }
		else if (ch == 'M') { out.meta  = neg ? Forbidden : Required; neg = false; }
		else if (ch == 'S') { out.shift = neg ? Forbidden : Required; neg = false; }
		else if (ch == 'R') { out.right = neg ? Forbidden : Required; neg = false; }

		c++;
	}

	if (*c == 0) {
		return false;
	}
	cmd = cmd.substr((c + 1) - cmd.c_str());

	return true;
}


static bool CheckCustomCmdMods(bool rmb, ModGroup& inMods)
{
	if (((inMods.alt   == Required)  && !keys[SDLK_LALT])   ||
	    ((inMods.alt   == Forbidden) &&  keys[SDLK_LALT])   ||
	    ((inMods.ctrl  == Required)  && !keys[SDLK_LCTRL])  ||
	    ((inMods.ctrl  == Forbidden) &&  keys[SDLK_LCTRL])  ||
	    ((inMods.meta  == Required)  && !keys[SDLK_LMETA])  ||
	    ((inMods.meta  == Forbidden) &&  keys[SDLK_LMETA])  ||
	    ((inMods.shift == Required)  && !keys[SDLK_LSHIFT]) ||
	    ((inMods.shift == Forbidden) &&  keys[SDLK_LSHIFT]) ||
	    ((inMods.right == Required)  && !rmb)               ||
	    ((inMods.right == Forbidden) &&  rmb)) {
		return false;
	}
	return true;
}


void CGuiHandler::RunCustomCommands(const vector<string>& cmds, bool rmb)
{
	static int depth = 0;
	if (depth > 8) {
		return; // recursion protection
	}
	depth++;

	for (int p = 0; p < (int)cmds.size(); p++) {
		string copy = cmds[p];
		ModGroup inMods;  // must match for the action to execute
		ModGroup outMods; // controls the state of the modifiers  (ex: "group1")
		if (ParseCustomCmdMods(copy, inMods, outMods)) {
			if (CheckCustomCmdMods(rmb, inMods)) {
				const bool tmpAlt   = !!keys[SDLK_LALT];
				const bool tmpCtrl  = !!keys[SDLK_LCTRL];
				const bool tmpMeta  = !!keys[SDLK_LMETA];
				const bool tmpShift = !!keys[SDLK_LSHIFT];
				if (outMods.alt   == Required)  { keys[SDLK_LALT]   = 1; }
				if (outMods.alt   == Forbidden) { keys[SDLK_LALT]   = 0; }
				if (outMods.ctrl  == Required)  { keys[SDLK_LCTRL]  = 1; }
				if (outMods.ctrl  == Forbidden) { keys[SDLK_LCTRL]  = 0; }
				if (outMods.meta  == Required)  { keys[SDLK_LMETA]  = 1; }
				if (outMods.meta  == Forbidden) { keys[SDLK_LMETA]  = 0; }
				if (outMods.shift == Required)  { keys[SDLK_LSHIFT] = 1; }
				if (outMods.shift == Forbidden) { keys[SDLK_LSHIFT] = 0; }

				CKeyBindings::Action action(copy);
				if (!ProcessLocalActions(action)) {
					CKeySet ks;
					game->ActionPressed(action, ks, false /*isRepeat*/);
				}

				keys[SDLK_LALT]   = tmpAlt;
				keys[SDLK_LCTRL]  = tmpCtrl;
				keys[SDLK_LMETA]  = tmpMeta;
				keys[SDLK_LSHIFT] = tmpShift;
			}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?