/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #ifndef _EXGRIPCONTEXTMENU_H_INCLUDED_ #define _EXGRIPCONTEXTMENU_H_INCLUDED_ #include "OdDbStub.h" #include "DbCommandContext.h" #include "Gi/GiDrawableImpl.h" #include "Gi/GiViewportGeometry.h" #include "Gi/GiViewportDraw.h" #include "Gi/GiTextStyle.h" #include "Ge/GeLineSeg3d.h" #include "Gi/Gi.h" class ExGripContextMenu : public OdEdPointTracker, OdGiDrawableImpl<> { struct Item { OdString text; int id; }; OdArray items; OdGePoint3d cursor; OdGePoint3d base; mutable OdGePoint3d rect[4]; mutable int selItemIndex; mutable OdGiTextStyle style; mutable double itemHeight; mutable double height, width; mutable double indent; mutable OdGeMatrix3d xWorldToMenu; mutable double hotDist; public: void addItem(const OdString& text, int id = -1) { Item* item = items.append(); item->text = text; item->id = id; selItemIndex = -1; height = -1.; // not initialized } int trackPopupMenu(OdEdCommandContext* pEdCmdCtx, const OdGePoint3d& pointWCS, OdUInt32 flags = 0) { base = pointWCS; int result = -1; try { OdDbCommandContextPtr(pEdCmdCtx)->dbUserIO()->getPoint( "Select option:", OdEd::kInpThrowEmpty, 0, OdString::kEmpty, this); result = selectedItemId(); if(result==-1) result = selectedItemIndex(); } catch(const OdEdEmptyInput& ) { } catch(const OdEdCancel& ) { } catch(const OdError& ) { } return result; } int selectedItemIndex() const { return selItemIndex; } OdString selectedItemText() const { return selItemIndex >= 0 ? items[selItemIndex].text : OdString::kEmpty; } int selectedItemId() const { return selItemIndex >= 0 ? items[selItemIndex].id : -1; } protected: virtual void setValue(const OdGePoint3d& value) { cursor = value; if(height < 0.) return; OdGePoint3d cursorMenu = xWorldToMenu * cursor; if(cursorMenu.x < -indent || cursorMenu.x > rect[1].x+indent || cursorMenu.y > indent || cursorMenu.y < rect[2].y-indent*3) throw OdEdCancel(); } virtual int addDrawables(OdGsView* pView) { pView->add(this, 0); return 1; } virtual void removeDrawables(OdGsView* pView) { pView->erase(this); } virtual OdUInt32 subSetAttributes(OdGiDrawableTraits * traits) const { return kDrawableIsAnEntity; } virtual bool subWorldDraw(OdGiWorldDraw * wd) const { return false; } static OdCmEntityColor fromCOLOREF(ODCOLORREF rgba) { OdCmEntityColor cmc(OdCmEntityColor::kByColor); cmc.setRGB(ODGETRED(rgba), ODGETGREEN(rgba), ODGETBLUE(rgba)); return cmc; } virtual void subViewportDraw(OdGiViewportDraw * vd) const { OdGiViewportGeometry& geom = vd->geometry(); OdGeVector3d norm = vd->viewport().viewDir(); OdGeVector3d x = norm.perpVector(); OdGeVector3d y = x.perpVector(); initMenu(*vd->context()); rect[0].set(itemHeight, -itemHeight, 0.); rect[1].set(itemHeight+width, -itemHeight, 0.); rect[2].set(itemHeight+width, -itemHeight-height, 0.); rect[3].set(itemHeight, -itemHeight-height, 0.); OdGeMatrix3d xEyeToWorld = vd->viewport().getEyeToWorldTransform(); OdGeMatrix3d xWorldToEye = vd->viewport().getWorldToEyeTransform(); OdGePoint2d pixDens; vd->viewport().getNumPixelsInUnitSquare(base, pixDens, false); OdGeMatrix3d xMenuToWorld = xEyeToWorld * OdGeMatrix3d::translation((xWorldToEye * base).asVector()) * OdGeMatrix3d::scaling(12/pixDens.x); xWorldToMenu = xMenuToWorld.inverse(); geom.pushModelTransform(xMenuToWorld); OdGiSubEntityTraits& traits = vd->subEntityTraits(); traits.setLineWeight(OdDb::kLnWt000); traits.setFillType(kOdGiFillAlways); OdCmEntityColor bckg = fromCOLOREF(vd->context()->paletteBackground()); traits.setTrueColor(bckg); geom.polygon(4, rect, &norm); traits.setFillType(kOdGiFillNever); traits.setTrueColor(OdCmEntityColor(128,128,128)); geom.polygon(4, rect, &norm); OdGePoint3d cursorMenu = xWorldToMenu * cursor; OdGePoint3d pt(itemHeight+indent, -itemHeight-itemHeight, 0.); selItemIndex = -1; for(OdUInt32 i=0, n=items.size(); i itemHeight && cursorMenu.x < itemHeight+width && cursorMenu.y < rect[0].y && cursorMenu.y > rect[2].y) { traits.setFillType(kOdGiFillAlways); traits.setColor(7); geom.polygon(4, rect, &norm); traits.setTrueColor(bckg); selItemIndex = i; } else { traits.setColor(7); } geom.text(pt, norm, x, item.text.c_str(), item.text.getLength(), false, &style); geom.text(pt+OdGeVector3d(.055,.055,0.), norm, x, item.text.c_str(), item.text.getLength(), false, &style); pt.y -= itemHeight; } geom.popModelTransform(); } void initMenu(OdGiContext& ctx) const { if(height >= 0.) return; style.setTextSize(1.); itemHeight = 1.75; indent = 0.3; height = itemHeight * items.size() + indent * 2.; hotDist = 2.; width = 0.; for(OdUInt32 i=0, n=items.size(); i