Example #1
3
/**
 \brief Draw a target circle and threshold along with the current pad position.
 \param idX the ID of the horizontal axis
 \param idY the ID of the vertical axis
 \param axesValues the axes raw values
 \param threshRadius the radius of the filtering threshold
 \ingroup ControllerTest
 */
void drawPadTarget(const int idX, const int idY, const std::vector<float> & axesValues, const float threshRadius){
	const ImU32 whiteColor = IM_COL32(255,255,255, 255);
	const int aidRX = idX;
	const int aidRY = idY;
	const float magRX = aidRX >= 0 ? axesValues[aidRX] : 0.0f;
	const float magRY = aidRY >= 0 ? axesValues[aidRY] : 0.0f;
	// Detect overflow on each axis.
	const bool overflow = (std::abs(magRX) > 1.0) || (std::abs(magRY) > 1.0);
	// Get current rendering position on screen.
	const ImVec2 posR = ImGui::GetCursorScreenPos();
	ImDrawList * drawListR = ImGui::GetWindowDrawList();
	// Draw "safe" region.
	drawListR->AddRectFilled(posR, ImVec2(posR.x + 200, posR.y + 200), overflow ? IM_COL32(30,0,0,255) : IM_COL32(0,30,0, 255));
	drawListR->AddCircleFilled(ImVec2(posR.x + 100, posR.y + 100), threshRadius, IM_COL32(0, 0, 0, 255), 32);
	// Draw frame and cross lines.
	drawListR->AddRect(posR, ImVec2(posR.x + 200, posR.y + 200), overflow ? IM_COL32(255,0,0, 255) : whiteColor);
	drawListR->AddLine(ImVec2(posR.x + 100, posR.y), ImVec2(posR.x + 100, posR.y+200), whiteColor);
	drawListR->AddLine(ImVec2(posR.x, posR.y + 100), ImVec2(posR.x + 200, posR.y+100), whiteColor);
	// Draw threshold and unit radius circles.
	drawListR->AddCircle(ImVec2(posR.x + 100, posR.y + 100), threshRadius, IM_COL32(0, 255, 0, 255), 32);
	drawListR->AddCircle(ImVec2(posR.x + 100, posR.y + 100), 100, whiteColor, 32);
	// Current axis position.
	drawListR->AddCircleFilled(ImVec2(posR.x + magRX * 100 + 100, posR.y + magRY * 100 + 100), 10, whiteColor);
}
void CGUIManager::Draw()
{
	ImGui::SetNextWindowPos(ImVec2(-1000, -1000));
	ImGui::SetNextWindowSize(ImVec2(100000, 100000));
	if (ImGui::Begin("GlobalScreen", nullptr, ImVec2(0, 0), 0.0f,
		ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoInputs))
	{
		ImDrawList * DrawList = ImGui::GetWindowDrawList();

		for (auto Text : TextQueue)
		{
			DrawList->AddText(ImVec2((float) Text.Position.X, (float) Text.Position.Y), 0xFFFFFFFF, Text.Text.c_str());
		}
		TextQueue.clear();

		ImGui::End();
	}
	ImGui::Render();
}
Example #3
1
/**
 \brief Draw a target line and threshold along with the current trigger position.
 \param idT the ID of the trigger axis
 \param axesValues the axes raw values
 \param threshRadius the value of the filtering threshold
 \ingroup ControllerTest
 */
void drawTriggerTarget(const int idT, const std::vector<float> & axesValues, const float threshRadius){
	const ImU32 whiteColor = IM_COL32(255,255,255, 255);
	const int aidLT = idT;
	const float magLT = aidLT >= 0 ? axesValues[aidLT]*0.5+0.5f : 0.0f;
	// Detect overflow.
	const bool overflow = (magLT > 1.0f || magLT < 0.0f);
	// Get current rendering position on screen.
	const ImVec2 posR = ImGui::GetCursorScreenPos();
	ImDrawList * drawListR = ImGui::GetWindowDrawList();
	const float thresholdY = (200.0f-2.0f*threshRadius);
	const float currentY = 200*(1.0f-magLT);
	// Draw "safe" region.
	drawListR->AddRectFilled(posR, ImVec2(posR.x+40, posR.y+thresholdY), overflow ? IM_COL32(30,0,0,255) : IM_COL32(0,30,0, 255));
	// Draw threshold line.
	drawListR->AddLine(ImVec2(posR.x, posR.y + thresholdY), ImVec2(posR.x + 40, posR.y+thresholdY), IM_COL32(0, 255, 0, 255));
	// Draw frame.
	drawListR->AddRect(posR, ImVec2(posR.x + 40, posR.y + 200), overflow ? IM_COL32(255,0,0, 255) : whiteColor);
	// Current axis position.
	drawListR->AddLine(ImVec2(posR.x, posR.y + currentY), ImVec2(posR.x + 40, posR.y + currentY), whiteColor, 4.0f);
}
Example #4
0
static void fillRectangle(Scintilla::PRectangle _rc, Scintilla::ColourDesired _color)
{
	const uint32_t abgr = (uint32_t)_color.AsLong();

	ImVec2 pos = ImGui::GetCursorScreenPos();

	ImDrawList* drawList = ImGui::GetWindowDrawList();
	drawList->AddDrawCmd();
	drawList->AddRectFilled(
		  ImVec2(_rc.left  + pos.x, _rc.top    + pos.y)
		, ImVec2(_rc.right + pos.x, _rc.bottom + pos.y)
		, abgr
		);
}
void TransferFunctionUi::drawThresholdControl()
{
    // draw threshold indicator
    const ImVec2 p = ui::GetCursorScreenPos();
    ImDrawList* drawList = ui::GetWindowDrawList();
    auto width = ui::GetContentRegionAvailWidth();
    ImU32 gray = ImColor(0.5f, 0.5f, 0.5f, 0.5f);
    float x = p.x;
    float y = p.y - 35.0f - 4.0f;
    float steps = width / 255;
    ImGuiStyle& style = ui::GetStyle();
    auto threshold = getThreshold();

    if (threshold.x > 0)
    {
        drawList->AddRectFilled(ImVec2(x, y - 120), ImVec2(x + threshold.x * steps, y), gray, style.FrameRounding);
    }

    if (threshold.y < 255)
    {
        drawList->AddRectFilled(ImVec2(x + threshold.y * steps, y - 120), ImVec2(x + 255 * steps, y), gray, style.FrameRounding);
    }

    // draw threshold controls
    ui::BeginGroup();
    ui::PushItemWidth(-2.0f);

    if (ui::SliderInt2("##Threshold", value_ptr(threshold), 0, 255))
    {
        setThreshold(threshold.x, threshold.y);
        updateFunction();
    }

    ui::PopItemWidth();
    ui::EndGroup();
}
void TransferFunctionUi::drawControlPointsUi()
{
    const ImVec2 p = ui::GetCursorScreenPos();
    ImDrawList* drawList = ui::GetWindowDrawList();
    int width = ui::GetContentRegionAvailWidth() - 4.0f;
    ImU32 white = ImColor(1.0f, 1.0f, 1.0f, 1.0f);
    ImU32 black = ImColor(0.0f, 0.0f, 0.0f, 1.0f);
    float sz = 20.0f;
    float x = p.x + 4.0f;
    float y = p.y + 4.0f;
    float step = static_cast<float>(width) / 256;
    auto& colorPoints = getColorPoints();
    auto& alphaPoints = getAlphaPoints();

    for (int i = 0; i < 256; i++)
    {
        const auto& color = getColor(i);
        ImU32 col32 = ImColor(color);
        // draw color transfer function
        drawList->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col32, 2.0f * step);
        x += step;
    }

    for (auto& colorP : colorPoints)
    {
        const auto& color = colorP.getColor();
        ImU32 col32 = ImColor(color.r, color.g, color.b, 1.0f);
        ImU32 invCol32 = ImColor(1.0f - color.r, 1.0f - color.g, 1.0f - color.b, 1.0f);
        drawList->AddCircleFilled(ImVec2(p.x + step * colorP.getIsoValue() + 4.0f, y + sz), 5, col32, 24);
        drawList->AddCircle(ImVec2(p.x + step * colorP.getIsoValue() + 4.0f, y + sz), 5, invCol32, 24);
    }

    for (int i = 0; i < 255; i++)
    {
        auto aBegin = clamp(1.0f - getColor(i).a, 0.0f, 1.0f);
        auto aEnd = clamp(1.0f - getColor(i + 1).a, 0.0f, 1.0f);
        drawList->AddLine(ImVec2(p.x + step * i + 4.0f, y - 124.0f + aBegin * 120),
            ImVec2(p.x + step * (i + 1) + 4.0f, y - 124.0f + aEnd * 120), white, 2);
    }

    for (auto& alphaP : alphaPoints)
    {
        const auto& alpha = 1.0f - alphaP.getAlpha();
        ImU32 opacity = ImColor(1.0f - vec4(alpha));
        drawList->AddCircleFilled(ImVec2(p.x + step * alphaP.getIsoValue() + 4.0f, y - 124.0f + alpha * 120), 5, opacity, 24);
        drawList->AddCircle(ImVec2(p.x + step * alphaP.getIsoValue() + 4.0f, y - 124.0f + alpha * 120), 5, black, 24);
    }

    ui::Dummy(ImVec2(width, sz + 15.0f));
}
Example #7
0
/**
 The main function of the controller tester.
 \param argc the number of input arguments.
 \param argv a pointer to the raw input arguments.
 \return a general error code.
 \ingroup ControllerTest
 */
int main(int argc, char** argv) {
	
	// First, init/parse/load configuration.
	RenderingConfig config(std::vector<std::string>(argv, argv+argc));
	// Override window dimensions.
	
	config.initialWidth = 800;
	config.initialHeight = 800;
	GLFWwindow* window = Interface::initWindow("Controller test", config);
	if(!window){
		return -1;
	}
	
	// Enable raw mode for the input, that way all controllers will be raw controllers.
	Input::manager().preferRawControllers(true);
	
	// Will contain reference button/axes to raw input mappings.
	std::vector<int> buttonsMapping(Controller::ControllerInputCount, -1);
	std::vector<int> axesMapping(Controller::ControllerInputCount, -1);
	// Controller texture.
	const GLuint controllerTexId = Resources::manager().getTexture("ControllerLayout", {GL_RGBA8})->id;
	
	bool firstFrame = true;
	const ImU32 highlightColor = IM_COL32(172, 172, 172, 255);
	
	float threshold = 0.02f;
	
	// Start the display/interaction loop.
	while (!glfwWindowShouldClose(window)) {
		// Update events (inputs,...).
		Input::manager().update();
		// Handle quitting.
		if(Input::manager().pressed(Input::KeyEscape)){
			glfwSetWindowShouldClose(window, GL_TRUE);
		}
		
		// Reload resources.
		if(Input::manager().triggered(Input::KeyP)){
			Resources::manager().reload();
		}
		
		// Detect either a new connected controller or a first frame with an already connected controller.
		if(Input::manager().controllerConnected() || (firstFrame && Input::manager().controllerAvailable())){
			firstFrame = false;
			const RawController * controller = static_cast<RawController*>(Input::manager().controller());
			const int axesCount = int(controller->allAxes.size());
			const int buttonsCount = int(controller->allButtons.size());
			
			// Check if some elements were already modified.
			bool wereEmpty = true;
			for(int i = 0; i < int(buttonsMapping.size()); ++i){
				if(wereEmpty && buttonsMapping[i] >= 0){
					wereEmpty = false;
				}
				// Update mapping for extraneous button IDs.
				if(buttonsMapping[i] >= buttonsCount){
					buttonsMapping[i] = -1;
				}
			}
			for(int i = 0; i < int(axesMapping.size()); ++i){
				if(wereEmpty && axesMapping[i] >= 0){
					wereEmpty = false;
				}
				if(axesMapping[i] >= axesCount){
					axesMapping[i] = -1;
				}
			}
		
			// If everything was -1 (first launch), attribute the buttons and axes sequentially, just to help with the visualisation and assignment.
			if(wereEmpty){
				for(int i = 0; i < std::min(int(buttonsMapping.size()), buttonsCount); ++i){
					buttonsMapping[i] = i;
				}
				// Start from the end for the axes.
				for(int i = 0; i < std::min(int(axesMapping.size()), axesCount); ++i){
					const int actionId = int(axesMapping.size()) - 1 - i;
					// Avoid double mappings.
					if(buttonsMapping[actionId] >= 0){
						continue;
					}
					axesMapping[actionId] = i;
				}
			}
		}
		
		// Start a new frame for the interface.
		Interface::beginFrame();
		
		// Render nothing.
		const glm::vec2 screenSize = Input::manager().size();
		glViewport(0, 0, (GLsizei)screenSize[0], (GLsizei)screenSize[1]);
		glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);
		
		// Set a fullscreen fixed window.
		ImGui::SetNextWindowPos(ImVec2(0,0));
		ImGui::SetNextWindowBgAlpha(1.0f);
		ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize);
		const ImGuiWindowFlags windowOptions = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoTitleBar;
		
		if(ImGui::Begin("Controller", nullptr, windowOptions)){
			if(!Input::manager().controllerAvailable()){
				ImGui::Text("No controller connected.");
			} else {
				// Load/save configuration files.
				if(ImGui::Button("Load...")){
					std::string inputPath;
					const bool res = Interface::showPicker(Interface::Picker::Load, "", inputPath);
					if(res && !inputPath.empty()){
						const std::string settingsContent = Resources::manager().loadStringFromExternalFile(inputPath);
						Controller::parseConfiguration(settingsContent, axesMapping, buttonsMapping);
					}
				}
				ImGui::SameLine();
				if(ImGui::Button("Save...")){
					std::string outputPath;
					const bool res = Interface::showPicker(Interface::Picker::Save, "", outputPath);
					if(res && !outputPath.empty()){
						const Controller * controller = Input::manager().controller();
						Controller::saveConfiguration(outputPath, controller->guid(), controller->name(), axesMapping, buttonsMapping);
					}
				}
				ImGui::Separator();
				
				// Infos on the controller.
				RawController * controller = static_cast<RawController*>(Input::manager().controller());
				const int axesCount = int(controller->allAxes.size());
				const int buttonsCount = int(controller->allButtons.size());
				ImGui::Text("%s, id: %d, axes: %d, buttons: %d", controller->name().c_str(), controller->id(), axesCount, buttonsCount);
				
				// Display raw axes and buttons and update their display when the user interacts with them.
				if(ImGui::CollapsingHeader("Raw inputs##HEADER", ImGuiTreeNodeFlags_DefaultOpen)){
					ImGui::Columns(2);
					
					for(int aid = 0; aid < axesCount; ++aid){
						const std::string axisName = "A" + std::to_string(aid);
						ImGui::SliderFloat(axisName.c_str(), &controller->allAxes[aid], -1.0f, 1.0f);
						ImGui::NextColumn();
					}
					ImGui::Columns(1);
					ImGui::Separator();
					ImGui::Columns(10);
					for(int bid = 0; bid < buttonsCount; ++bid){
						const std::string buttonName = "B" + std::to_string(bid);
						ImGui::RadioButton(buttonName.c_str(), controller->allButtons[bid].pressed);
						ImGui::NextColumn();
					}
					ImGui::Columns(1);
				}
				
			
				if(ImGui::CollapsingHeader("Assignment##HEADER", ImGuiTreeNodeFlags_DefaultOpen)){
					// Display the controller layout, highlight pressed buttons.
					ImGui::BeginChild("##ControllerLayout", ImVec2(450, 300));
					// Get current rnedering position on screen.
					const ImVec2 pos = ImGui::GetCursorScreenPos();
					ImDrawList * drawList = ImGui::GetWindowDrawList();
					
					// Render the left pad first.
					const int aidLX = axesMapping[Controller::PadLeftX];
					const int aidLY = axesMapping[Controller::PadLeftY];
					const float magLX = aidLX >= 0 ? controller->allAxes[aidLX] : 0.0f;
					const float magLY = aidLY >= 0 ? controller->allAxes[aidLY] : 0.0f;
					if((aidLX >= 0 || aidLY >= 0) && (magLX*magLX + magLY*magLY > threshold)){
						drawList->AddCircleFilled(ImVec2(pos.x+154, pos.y+179), 34, highlightColor);
						drawList->AddCircleFilled(ImVec2(pos.x+154, pos.y+179), 26, IM_COL32(0, 0, 0, 255));
					}
					
					// Then the right pad.
					const int aidRX = axesMapping[Controller::PadRightX];
					const int aidRY = axesMapping[Controller::PadRightY];
					const float magRX = aidRX >= 0 ? controller->allAxes[aidRX] : 0.0f;
					const float magRY = aidRY >= 0 ? controller->allAxes[aidRY] : 0.0f;
					if((aidRX >= 0 || aidRY >= 0) && (magRX*magRX + magRY*magRY > threshold)){
						drawList->AddCircleFilled(ImVec2(pos.x+296, pos.y+179), 34, highlightColor);
						drawList->AddCircleFilled(ImVec2(pos.x+296, pos.y+179), 26, IM_COL32(0, 0, 0, 255));
					}
					
					// Render the left trigger (assuming its default value is -1.0).
					const int aidLT = axesMapping[Controller::TriggerL2];
					const float magLT = aidLT >= 0 ? controller->allAxes[aidLT]*0.5+0.5f : 0.0f;
					if(aidLT >= 0 && (magLT*magLT > threshold)){
						drawButton(drawList, Controller::TriggerL2, pos, highlightColor);
					}
					// And the right trigger (assuming its default value is -1.0).
					const int aidRT = axesMapping[Controller::TriggerR2];
					const float magRT = aidRT >= 0 ? controller->allAxes[aidRT]*0.5+0.5f : 0.0f;
					if(aidRT >= 0 && (magRT*magRT > threshold)){
						drawButton(drawList, Controller::TriggerR2, pos, highlightColor);
					}
					
					// Render each button if active.
					for(int bid = 0; bid < int(buttonsMapping.size()); ++bid){
						const int bmid = buttonsMapping[bid];
						if(bmid >= 0 && controller->allButtons[bmid].pressed){
							drawButton(drawList, Controller::ControllerInput(bid), pos, highlightColor);
						}
					}
					
					// Overlay the controller transparent texture.
					ImGui::Image(reinterpret_cast<void*>(controllerTexId), ImVec2(450, 300), ImVec2(0, 1), ImVec2(1,0));
					
					ImGui::EndChild();
					ImGui::SameLine();
					
					// Display combo selectors to assign raw input to each button.
					ImGui::BeginChild("##Layout selection", ImVec2(0, 300));
					ImGui::PushItemWidth(80);
					const int spacing = 160;
					
					showCombo("A", buttonsCount, "B", buttonsMapping[Controller::ButtonA]); ImGui::SameLine(spacing);
					showCombo("B", buttonsCount, "B", buttonsMapping[Controller::ButtonB]);
					showCombo("X", buttonsCount, "B", buttonsMapping[Controller::ButtonX]); ImGui::SameLine(spacing);
					showCombo("Y", buttonsCount, "B", buttonsMapping[Controller::ButtonY]);
					
					showCombo("Up", buttonsCount, "B", buttonsMapping[Controller::ButtonUp]); ImGui::SameLine(spacing);
					showCombo("Left", buttonsCount, "B", buttonsMapping[Controller::ButtonLeft]);
					showCombo("Down", buttonsCount, "B", buttonsMapping[Controller::ButtonDown]); ImGui::SameLine(spacing);
					showCombo("Right", buttonsCount, "B", buttonsMapping[Controller::ButtonRight]);
					
					showCombo("L1", buttonsCount, "B", buttonsMapping[Controller::BumperL1]); ImGui::SameLine(spacing);
					showCombo("R1", buttonsCount, "B", buttonsMapping[Controller::BumperR1]);
					showCombo("L2", buttonsCount, "B", buttonsMapping[Controller::TriggerL2]); ImGui::SameLine(spacing);
					showCombo("R2", buttonsCount, "B", buttonsMapping[Controller::TriggerR2]);
					showCombo("L3", buttonsCount, "B", buttonsMapping[Controller::ButtonL3]); ImGui::SameLine(spacing);
					showCombo("R3", buttonsCount, "B", buttonsMapping[Controller::ButtonR3]);
					
					showCombo("Menu", buttonsCount, "B", buttonsMapping[Controller::ButtonMenu]); ImGui::SameLine(spacing);
					showCombo("View", buttonsCount, "B", buttonsMapping[Controller::ButtonView]);
					showCombo("Logo", buttonsCount, "B", buttonsMapping[Controller::ButtonLogo]);
					
					ImGui::Separator();
					showCombo("Left X", axesCount, "A", axesMapping[Controller::PadLeftX]);  ImGui::SameLine(spacing);
					showCombo("Left Y", axesCount, "A", axesMapping[Controller::PadLeftY]);
					showCombo("Right X", axesCount, "A", axesMapping[Controller::PadRightX]);  ImGui::SameLine(spacing);
					showCombo("Right Y", axesCount, "A", axesMapping[Controller::PadRightY]);
					showCombo("L. trigger", axesCount, "A", axesMapping[Controller::TriggerL2]); ImGui::SameLine(spacing);
					showCombo("R. trigger", axesCount, "A", axesMapping[Controller::TriggerR2]);
					
					ImGui::PopItemWidth();
					// Add threshold setup slider.
					ImGui::PushItemWidth(240);
					ImGui::SliderFloat("Threshold", &threshold, 0.0f, 0.3f);
					ImGui::PopItemWidth();
					ImGui::EndChild();
				}
				
				// Display targets with the current axis positions.
				if(ImGui::CollapsingHeader("Calibration##HEADER", ImGuiTreeNodeFlags_DefaultOpen)){
					
					const float threshRadius = sqrt(threshold) * 100;
					// Titles.
					ImGui::Text("Left pad & trigger"); ImGui::SameLine(300); ImGui::Text("Right pad & trigger");
					
					// Left pad.
					ImGui::BeginChild("PadLeftTarget", ImVec2(200, 200));
					drawPadTarget(axesMapping[Controller::PadLeftX], axesMapping[Controller::PadLeftY], controller->allAxes, threshRadius);
					ImGui::EndChild();
					ImGui::SameLine(220);
					// Left trigger
					ImGui::BeginChild("TriggerL2", ImVec2(40, 200));
					drawTriggerTarget(axesMapping[Controller::TriggerL2], controller->allAxes, threshRadius);
					ImGui::EndChild();
					
					ImGui::SameLine(300);
					// Right pad.
					ImGui::BeginChild("PadRightTarget", ImVec2(200, 200));
					drawPadTarget(axesMapping[Controller::PadRightX], axesMapping[Controller::PadRightY], controller->allAxes, threshRadius);
					ImGui::EndChild();
					
					// Right trigger
					ImGui::SameLine(520);
					ImGui::BeginChild("TriggerR2", ImVec2(40, 200));
					drawTriggerTarget(axesMapping[Controller::TriggerR2], controller->allAxes, threshRadius);
					ImGui::EndChild();
					
					
					
				}
			}
		}
		ImGui::End();
		
		
		// Then render the interface.
		Interface::endFrame();
		//Display the result for the current rendering loop.
		glfwSwapBuffers(window);

	}
	
	// Clean the interface.
	Interface::clean();
	
	Resources::manager().clean();
	// Close GL context and any other GLFW resources.
	glfwDestroyWindow(window);
	glfwTerminate();
	
	return 0;
}
Example #8
0
    /* pOptionalHoveredIndex: a ptr to an optional int that is set to -1 if no tab label is hovered by the mouse.
     * pOptionalItemOrdering: an optional static array of unique integers from 0 to numTabs-1 that maps the tab label order. If one of the numbers is replaced by -1 the tab label is not visible (closed). It can be read/modified at runtime.
     * allowTabReorder (requires pOptionalItemOrdering): allows tab reordering through drag and drop (it modifies pOptionalItemOrdering).
     * allowTabClosingThroughMMB (requires pOptionalItemOrdering): closes the tabs when MMB is clicked on them, by setting the tab value in pOptionalItemOrdering to -1.
     * pOptionalClosedTabIndex (requires allowTabClosingThroughMMB): out variable (int pointer) that returns the index of the closed tab in last call or -1.
     * pOptionalClosedTabIndexInsideItemOrdering: same as above, but index of the pOptionalItemOrdering array.
    */
    IMGUI_API bool TabLabels(int numTabs, const char** tabLabels, int& selectedIndex, ImVec2 btnSize, const char** tabLabelTooltips, bool wrapMode, int *pOptionalHoveredIndex, int* pOptionalItemOrdering, bool allowTabReorder, bool allowTabClosingThroughMMB, int *pOptionalClosedTabIndex, int *pOptionalClosedTabIndexInsideItemOrdering) {
        ImGuiStyle& style = ImGui::GetStyle();

        const ImVec2 itemSpacing = style.ItemSpacing;
        const ImVec4 color = style.Colors[ImGuiCol_Button];
        const ImVec4 colorActive = style.Colors[ImGuiCol_ButtonActive];
        const ImVec4 colorHover = style.Colors[ImGuiCol_ButtonHovered];
        const ImVec4 colorText = style.Colors[ImGuiCol_Text];
        style.ItemSpacing.x = 10;
        style.ItemSpacing.y = 10;
        style.FrameRounding = 2.0;

        const ImVec4 colorSelectedTab(color.x,color.y,color.z,color.w*0.5f);
        const ImVec4 colorSelectedTabHovered(colorHover.x,colorHover.y,colorHover.z,colorHover.w*0.5f);
        const ImVec4 colorSelectedTabText(colorText.x*0.8f,colorText.y*0.8f,colorText.z*0.6f,colorText.w*0.8f);
        //ImGui::ClampColor(colorSelectedTabText);

        if (numTabs>0 && (selectedIndex<0 || selectedIndex>=numTabs)) {
            if (!pOptionalItemOrdering)  selectedIndex = 0;
            else selectedIndex = -1;
        }
        if (pOptionalHoveredIndex) *pOptionalHoveredIndex = -1;
        if (pOptionalClosedTabIndex) *pOptionalClosedTabIndex = -1;
        if (pOptionalClosedTabIndexInsideItemOrdering) *pOptionalClosedTabIndexInsideItemOrdering = -1;

        float windowWidth = 0.f,sumX=0.f;
        if (wrapMode) windowWidth = ImGui::GetWindowWidth() - style.WindowPadding.x - (ImGui::GetScrollMaxY()>0 ? style.ScrollbarSize : 0.f);

        static int draggingTabIndex = -1;int draggingTabTargetIndex = -1;   // These are indices inside pOptionalItemOrdering
        static ImVec2 draggingTabSize(0,0);
        static ImVec2 draggingTabOffset(0,0);

        const bool isMMBreleased = ImGui::IsMouseReleased(2);
        const bool isMouseDragging = ImGui::IsMouseDragging(0,2.f);
        int justClosedTabIndex = -1,newSelectedIndex = selectedIndex;


        bool selection_changed = false;bool noButtonDrawn = true;
        for (int j = 0,i; j < numTabs; j++)
        {
            i = pOptionalItemOrdering ? pOptionalItemOrdering[j] : j;
            if (i==-1) continue;

            if (!wrapMode) {if (!noButtonDrawn) ImGui::SameLine();}
            else if (sumX > 0.f) {
                sumX+=style.ItemSpacing.x;   // Maybe we can skip it if we use SameLine(0,0) below
                sumX+=ImGui::CalcTextSize(tabLabels[i]).x+2.f*style.FramePadding.x;
                if (sumX>windowWidth) sumX = 0.f;
                else ImGui::SameLine();
            }

            if (i == selectedIndex) {
                // Push the style
                style.Colors[ImGuiCol_Button] =         colorSelectedTab;
                style.Colors[ImGuiCol_ButtonActive] =   colorSelectedTab;
                style.Colors[ImGuiCol_ButtonHovered] =  colorSelectedTabHovered;
                style.Colors[ImGuiCol_Text] =           colorSelectedTabText;
            }
            // Draw the button
            ImGui::PushID(i);   // otherwise two tabs with the same name would clash.
            if (ImGui::Button(tabLabels[i], btnSize))   {selection_changed = (selectedIndex!=i);newSelectedIndex = i;}
            ImGui::PopID();
            if (i == selectedIndex) {
                // Reset the style
                style.Colors[ImGuiCol_Button] =         color;
                style.Colors[ImGuiCol_ButtonActive] =   colorActive;
                style.Colors[ImGuiCol_ButtonHovered] =  colorHover;
                style.Colors[ImGuiCol_Text] =           colorText;
            }
            noButtonDrawn = false;

            if (wrapMode) {
                if (sumX==0.f) sumX = style.WindowPadding.x + ImGui::GetItemRectSize().x; // First element of a line
            }
            else if (isMouseDragging && allowTabReorder && pOptionalItemOrdering) {
                // We still need sumX
                if (sumX==0.f) sumX = style.WindowPadding.x + ImGui::GetItemRectSize().x; // First element of a line
                else sumX+=style.ItemSpacing.x + ImGui::GetItemRectSize().x;

            }

            if (ImGui::IsItemHoveredRect()) {
                if (pOptionalHoveredIndex) *pOptionalHoveredIndex = i;
                if (tabLabelTooltips && tabLabelTooltips[i] && strlen(tabLabelTooltips[i])>0)  ImGui::SetTooltip("%s",tabLabelTooltips[i]);

                if (pOptionalItemOrdering)  {
                    if (allowTabReorder)  {
                        if (isMouseDragging) {
                            if (draggingTabIndex==-1) {
                                draggingTabIndex = j;
                                draggingTabSize = ImGui::GetItemRectSize();
                                const ImVec2& mp = ImGui::GetIO().MousePos;
                                const ImVec2 draggingTabCursorPos = ImGui::GetCursorPos();
                                draggingTabOffset=ImVec2(
                                            mp.x+draggingTabSize.x*0.5f-sumX+ImGui::GetScrollX(),
                                            mp.y+draggingTabSize.y*0.5f-draggingTabCursorPos.y+ImGui::GetScrollY()
                                            );

                            }
                        }
                        else if (draggingTabIndex>=0 && draggingTabIndex<numTabs && draggingTabIndex!=j){
                            draggingTabTargetIndex = j; // For some odd reasons this seems to get called only when draggingTabIndex < i ! (Probably during mouse dragging ImGui owns the mouse someway and sometimes ImGui::IsItemHovered() is not getting called)
                        }
                    }
                    if (allowTabClosingThroughMMB)  {
                        if (isMMBreleased) {
                            justClosedTabIndex = i;
                            if (pOptionalClosedTabIndex) *pOptionalClosedTabIndex = i;
                            if (pOptionalClosedTabIndexInsideItemOrdering) *pOptionalClosedTabIndexInsideItemOrdering = j;
                            pOptionalItemOrdering[j] = -1;
                        }
                    }
                }
            }

        }

        selectedIndex = newSelectedIndex;

        // Draw tab label while mouse drags it
        if (draggingTabIndex>=0 && draggingTabIndex<numTabs) {
            const ImVec2& mp = ImGui::GetIO().MousePos;
            const ImVec2 wp = ImGui::GetWindowPos();
            ImVec2 start(wp.x+mp.x-draggingTabOffset.x-draggingTabSize.x*0.5f,wp.y+mp.y-draggingTabOffset.y-draggingTabSize.y*0.5f);
            const ImVec2 end(start.x+draggingTabSize.x,start.y+draggingTabSize.y);
            ImDrawList* drawList = ImGui::GetWindowDrawList();
            const float draggedBtnAlpha = 0.65f;
            const ImVec4& btnColor = style.Colors[ImGuiCol_Button];
            drawList->AddRectFilled(start,end,ImColor(btnColor.x,btnColor.y,btnColor.z,btnColor.w*draggedBtnAlpha),style.FrameRounding);
            start.x+=style.FramePadding.x;start.y+=style.FramePadding.y;
            const ImVec4& txtColor = style.Colors[ImGuiCol_Text];
            drawList->AddText(start,ImColor(txtColor.x,txtColor.y,txtColor.z,txtColor.w*draggedBtnAlpha),tabLabels[pOptionalItemOrdering[draggingTabIndex]]);

            ImGui::SetMouseCursor(ImGuiMouseCursor_Move);
        }

        // Drop tab label
        if (draggingTabTargetIndex!=-1) {
            // swap draggingTabIndex and draggingTabTargetIndex in pOptionalItemOrdering
            const int tmp = pOptionalItemOrdering[draggingTabTargetIndex];
            pOptionalItemOrdering[draggingTabTargetIndex] = pOptionalItemOrdering[draggingTabIndex];
            pOptionalItemOrdering[draggingTabIndex] = tmp;
            //fprintf(stderr,"%d %d\n",draggingTabIndex,draggingTabTargetIndex);
//            draggingTabTargetIndex = draggingTabIndex = -1;
        }

        // Reset draggingTabIndex if necessary
        if (!isMouseDragging) draggingTabIndex = -1;

        // Change selected tab when user closes the selected tab
        if (selectedIndex == justClosedTabIndex && selectedIndex>=0)    {
            selectedIndex = -1;
            for (int j = 0,i; j < numTabs; j++) {
                i = pOptionalItemOrdering ? pOptionalItemOrdering[j] : j;
                if (i==-1) continue;
                selectedIndex = i;
                break;
            }
        }

        // Restore the style
        style.Colors[ImGuiCol_Button] =         color;
        style.Colors[ImGuiCol_ButtonActive] =   colorActive;
        style.Colors[ImGuiCol_ButtonHovered] =  colorHover;
        style.Colors[ImGuiCol_Text] =           colorText;
        style.ItemSpacing =                     itemSpacing;

        return selection_changed;
    }
Example #9
0
PreviewTab::PreviewTab(Context* context)
    : Tab(context)
{
    SetID("d75264a1-4179-4350-8e9f-ec4e4a15a7fa");
    SetTitle("Game");
    isUtility_ = true;
    windowFlags_ = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
    view_ = context_->CreateObject<Texture2D>();

    // Ensure parts of texture are not left dirty when viewport does not cover entire texture.
    SubscribeToEvent(E_CAMERAVIEWPORTRESIZED, [this](StringHash, VariantMap& args) { Clear(); });
    // Ensure views are updated upon component addition or removal.
    SubscribeToEvent(E_COMPONENTADDED, [this](StringHash, VariantMap& args) {
        OnComponentUpdated(static_cast<Component*>(args[ComponentAdded::P_COMPONENT].GetPtr()));
    });
    SubscribeToEvent(E_COMPONENTREMOVED, [this](StringHash, VariantMap& args) {
        OnComponentUpdated(static_cast<Component*>(args[ComponentRemoved::P_COMPONENT].GetPtr()));
    });
    // Reload viewports when renderpath or postprocess was modified.
    SubscribeToEvent(E_RELOADFINISHED, [this](StringHash, VariantMap& args) {
        using namespace ReloadFinished;
        Scene* scene = GetSubsystem<SceneManager>()->GetActiveScene();
        if (scene == nullptr)
            return;

        if (auto* resource = GetEventSender()->Cast<Resource>())
        {
            if (resource->GetName().starts_with("RenderPaths/") || resource->GetName().starts_with("PostProcess/"))
            {
                if (auto* manager = scene->GetOrCreateComponent<SceneMetadata>())
                {
                    auto& viewportComponents = manager->GetCameraViewportComponents();
                    for (auto& component : viewportComponents)
                        component->RebuildRenderPath();
                    Clear();
                }
            }
        }
    });

    // On plugin code reload all scene state is serialized, plugin library is reloaded and scene state is unserialized.
    // This way scene recreates all plugin-provided components on reload and gets to use new versions of them.
    SubscribeToEvent(E_EDITORUSERCODERELOADSTART, [&](StringHash, VariantMap&) {

        SceneTab* tab = GetSubsystem<Editor>()->GetTab<SceneTab>();
        if (tab == nullptr || tab->GetScene() == nullptr)
            return;

        tab->GetUndo().SetTrackingEnabled(false);
        tab->SaveState(sceneReloadState_);
        tab->GetScene()->RemoveAllChildren();
        tab->GetScene()->RemoveAllComponents();
    });
    SubscribeToEvent(E_EDITORUSERCODERELOADEND, [&](StringHash, VariantMap&) {
        SceneTab* tab = GetSubsystem<Editor>()->GetTab<SceneTab>();
        if (tab == nullptr || tab->GetScene() == nullptr)
            return;

        tab->RestoreState(sceneReloadState_);
        tab->GetUndo().SetTrackingEnabled(true);
    });
    SubscribeToEvent(E_ENDALLVIEWSRENDER, [this](StringHash, VariantMap&) {
        RenderUI();
    });
    SubscribeToEvent(E_SCENEACTIVATED, [this](StringHash, VariantMap&) {
        UpdateViewports();
    });
    SubscribeToEvent(E_ENDRENDERINGSYSTEMUI, [this](StringHash, VariantMap&) {
        if (simulationStatus_ == SCENE_SIMULATION_STOPPED)
            dim_ = Max(dim_ - GetTime()->GetTimeStep() * 10, 0.f);
        else
            dim_ = Min(dim_ + GetTime()->GetTimeStep() * 6, 1.f);

        if (dim_ > M_EPSILON)
        {
            // Dim other windows except for preview.
            ImGuiContext& g = *ui::GetCurrentContext();
            const ea::string& sceneTabName = GetSubsystem<Editor>()->GetTab<SceneTab>()->GetUniqueTitle();
            for (int i = 0; i < g.Windows.Size; i++)
            {
                ImGuiWindow* window = g.Windows[i];
                if (window->ParentWindow != nullptr && window->DockNode != nullptr)
                {
                    // Ignore any non-leaf windows
                    if (window->DockNode->ChildNodes[0] || window->DockNode->ChildNodes[1])
                        continue;
                    if (!window->DockTabIsVisible)
                        continue;
                    // Editor scene viewport is not dimmed.
                    if (strcmp(window->Name, sceneTabName.c_str()) == 0)
                        continue;
                    // Game preview viewport is not dimmed.
                    if (strcmp(window->Name, GetUniqueTitle().c_str()) == 0)
                        continue;
                    ImDrawList* drawLists = ui::GetBackgroundDrawList(window->Viewport);
                    const ImU32 color = ui::GetColorU32(ImGuiCol_ModalWindowDimBg, dim_);
                    drawLists->AddRectFilled(window->Pos, window->Pos + window->Size, color);
                }
            }
        }
    });
}