HPS/3DF: How to create buttons/operators using subwindows

Below is sample code on how to create buttons using HPS API.

Sample code can be tested using hps_mfc_sandbox. Please replace the following functions in CHPSView.cpp.

Steps:

  1. Build and run hps_mfc_sandbox with sample code
  2. Click on UserCode3 (setup buttons)
  3. Load any model
  4. Click on button to activate corresponding operator

Notes:

We have an overload function to SetSubwindow(Rectangle const & position, IntRectangle const & offsets, Subwindow::Type type) which will make your buttons remain the same size.

The position values are still given as [-1,1] floats relative to the parent, but the offsets are pixel values relative to those.

Position gives a fractional location (where you measure from) and offset moves a fixed distance from that.For instance, you could make a subwindow that is always inset 25 pixels from its parent by specifying (-1,1,-1,1) & (25,-25,25,-25).

A 100x80 box stuck to the top-left corner would be (-1,-1,1,1) & (0, 100,-80,0).

A 10 pixel high along the top middle third of the parent would be (-0.333,0.333,1,1) & (0,0,-10,0).

Let’s say the two boxes are 50x50, 75 pixels from the bottom, and they are a bit left of center (let’s say centered about x = -0.1), one box could be (-0.1,-0.1,-1,-1) & (-50,0,75,126) and the other (-0.1,-0.1,-1,-1) & (0, 50, 75,125).

// Sample code to create two button on bottom of the scene

void CHPSView::OnUserCode2()
{
    HPS::SegmentKey subWindowSegment = GetCanvas().GetFrontView().GetSegmentKey().Down("subwindow", true);

	Point points[4] = { Point(0, 0, 0), Point(2, 0, 0), Point(2, 2, 0), Point(0, 2, 0) };
	int faces[5] = { 4, 0, 3, 2, 1 };


	subWindowSegment.GetTextAttributeControl().SetSize(6, HPS::Text::SizeUnits::Pixels).SetAlignment(Text::Alignment::Center);
	subWindowSegment.GetVisibilityControl().SetFaces(true).SetEdges(true).SetLights(false);


	HPS::SubwindowKit subwindowKit;
	subwindowKit.SetSubwindow(HPS::Rectangle(0,0, -1, -1),HPS::IntRectangle(-150, 0, -25, 100), HPS::Subwindow::Type::Lightweight);

	subWindowSegment.Subsegment("panOperator").InsertShell(4, points, 5, faces);
	subWindowSegment.Subsegment("panOperator").GetMaterialMappingControl().SetFaceColor(HPS::RGBAColor(0, 1, 0));
	subWindowSegment.Subsegment("panOperator").InsertText(HPS::Point(1, 1, 0), "PAN");
	subWindowSegment.Subsegment("panOperator").SetSubwindow(subwindowKit);


	HPS::SubwindowKit subwindowKit2;
	subwindowKit2.SetSubwindow(HPS::Rectangle(-0, 0, -1, -1), HPS::IntRectangle(-75, 50, -25, 100), HPS::Subwindow::Type::Lightweight);

	subWindowSegment.Subsegment("zoomOperator").InsertShell(4, points, 5, faces);
	subWindowSegment.Subsegment("zoomOperator").GetMaterialMappingControl().SetFaceColor(HPS::RGBAColor(0, 1, 0));
	subWindowSegment.Subsegment("zoomOperator").InsertText(HPS::Point(1, 1, 0), "ZOOM");
	subWindowSegment.Subsegment("zoomOperator").SetSubwindow(subwindowKit2);


	HPS::CameraKit cameraKit;
	cameraKit.SetUpVector(Vector(0, 1, 0));
	cameraKit.SetPosition(Point(0, 0, -10));
	cameraKit.SetTarget(Point(0, 0, 0));
	cameraKit.SetField(4, 4);
	cameraKit.SetProjection(HPS::Camera::Projection::Orthographic);
	subWindowSegment.SetCamera(cameraKit);


	//GetCanvas().GetFrontView().GetOperatorControl().Pop();
	//GetCanvas().GetFrontView().GetOperatorControl().Push(new MyOperatorControl(GetCanvas()), HPS::Operator::Priority::High);


	GetCanvas().UpdateWithNotifier().Wait();

}

// Sample code to test if button was selected

void CHPSView::OnLButtonDown(UINT nFlags, CPoint point)
{
	Point pixelPoint(point.x, point.y, 0);
	Point windowPoint;

	GetCanvas().GetWindowKey().ConvertCoordinate(HPS::Coordinate::Space::Pixel, pixelPoint, HPS::Coordinate::Space::Window, windowPoint);

	GetCanvas().GetWindowKey().GetSelectionOptionsControl().SetLevel(HPS::Selection::Level::Entity); // choosing entity-level selection
	GetCanvas().GetWindowKey().GetSelectionOptionsControl().SetProximity(0.01f);
	GetCanvas().GetWindowKey().GetSelectionOptionsControl().SetAlgorithm(HPS::Selection::Algorithm::Analytic);

    

	HPS::SelectionResults selectionResults;
	size_t numSelectedItems = GetCanvas().GetWindowKey().GetSelectionControl().SelectByPoint(  // this is the actual selection call
		windowPoint,        // the endpoint of the ray, typically the camera location
		selectionResults);
		
    // Check if button was button selected
	HPS::SelectionResultsIterator iter = selectionResults.GetIterator();
	while (iter.IsValid())
	{
		HPS::SelectionItem selectionItem = iter.GetItem();
		Key key;
		selectionItem.ShowSelectedItem(key); // 'key' is the HPS::Key of the selected item

		if (key.Type() == HPS::Type::ShellKey)
		{
			// do something with this key
			HPS::SegmentKey ownerSegment = key.Owner();

			if (ownerSegment.Name() == "panOperator")
			{
				GetCanvas().GetFrontView().GetOperatorControl().Pop();
				GetCanvas().GetFrontView().GetOperatorControl().Push(new HPS::PanOperator(MouseButtons::ButtonLeft()));
             
                // Highlight button 
                // Please see Highlight section for sample code.
			}

			if (ownerSegment.Name() == "zoomOperator")
			{
				GetCanvas().GetFrontView().GetOperatorControl().Pop();
				GetCanvas().GetFrontView().GetOperatorControl().Push(new HPS::ZoomOperator(MouseButtons::ButtonLeft()));
				
				// Highlight button 
                // Please see Highlight section for sample code.
			}
		}

		iter.Next();
	}


	SetCapture();
	_canvas.GetWindowKey().GetEventDispatcher().InjectEvent(
		BuildMouseEvent(HPS::MouseEvent::Action::ButtonDown, HPS::MouseButtons::ButtonLeft(), point, nFlags, 1));

	CView::OnLButtonDown(nFlags, point);
}

3DF API

The same type of thing can be achieved using the 3DF API.

Here is sample code to setup button in the scene graph.

//  Setup Buttons
void CSolidHoopsView::OnExtraSlot3() {

	HPoint	spts[4];
	int		facelist[5];

	spts[0].x = -0.5f; spts[0].y = -0.5f; spts[0].z = 0.0f;
	spts[1].x = 0.5f; spts[1].y = -0.5f; spts[1].z = 0.0f;
	spts[2].x = 0.5f; spts[2].y = 0.5f; spts[2].z = 0.0f;
	spts[3].x = -0.5f; spts[3].y = 0.5f; spts[3].z = 0.0f;

	facelist[0] = 4; facelist[1] = 0; facelist[2] = 1; facelist[3] = 2;
	facelist[4] = 3;

	HC_Open_Segment_By_Key(m_pHView->GetOverwriteKey()); {

		float position[] = { 0.0, 0.0, -5.0 };
		float target[] = { 0.0, 0.0, 0.0 };
		float up[] = { 0.0, 1.0, 0.0 };

		float field_width = 10;
		float field_height = 10;

		HC_Open_Segment("subwindow"); {		

			HC_Set_Visibility("lights=off");
			HC_Set_Camera(&position, &target, &up, field_width, field_height, "orthographic");
			
			HC_Set_Window_Pattern("clear");
			HC_Set_Visibility("faces=on,edges=on,text=on");
			HC_Set_Selectability("geometry=on,windows=on");

			HC_Open_Segment("panOperator"); {
				HC_Insert_Shell(4, spts, 5, facelist);
				HC_Insert_Text(0, 0, 0, "PAN");
				HC_Translate_Object(0, -4.5f, 0);
			} HC_Close_Segment();
			HC_Open_Segment("orbitOperator"); {
				HC_Translate_Object(1, -4.5f, 0);
				HC_Insert_Text(0, 0, 0, "ORB");

				HC_Insert_Shell(4, spts, 5, facelist);
			} HC_Close_Segment();

		} HC_Close_Segment();
											
	} HC_Close_Segment();

	m_pHView->Update();

}

In this case, the selection code is added to UserCode2 & 3.

This code checks to see if buttons are pressed and activates the operator.

void CSolidHoopsView::OnExtraSlot2() 
{
	int count;

	HC_Open_Segment_By_Key(m_pHView->GetViewKey()); {
		HC_Set_Selectability("everything = off,vertices = on!");
		//	HC_Set_Heuristics("related selection limit = 0");

			// Let's make our first selection.
		count = HC_Compute_Selection(".", "./scene/overwrite", "v", 0, -0.9f);

		if (count > 0)
		{
			do {
				char buffer[1024];
				HC_Show_Selection_Pathname(buffer);
				if (strstr(buffer, "panoperator"))
				{
					m_pHView->SetOperator(new HOpCameraPan(m_pHView))
				}

			} while (HC_Find_Related_Selection());
		}
	} HC_Close_Segment();

	m_pHView->Update();
}

void CSolidHoopsView::OnExtraSlot3() 
{
	int count;

	HC_Open_Segment_By_Key(m_pHView->GetViewKey()); {
		HC_Set_Selectability("everything = off,vertices = on!");
		//	HC_Set_Heuristics("related selection limit = 0");

			// Let's make our first selection.
		count = HC_Compute_Selection(".", "./scene/overwrite", "v", -0.1, -0.9f);
		if (count > 0)
		{
			do {

				char buffer[1024];
				HC_Show_Selection_Pathname(buffer);

				if (strstr(buffer, "orbitoperator"))
				{
					m_pHView->SetOperator(new HOpCameraOrbit(m_pHView));
				}

			} while (HC_Find_Related_Selection());
		}
	} HC_Close_Segment();

	m_pHView->Update();

}