AsdkPromptBase.h 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2015 Autodesk, Inc. All rights reserved.
  4. //
  5. // Use of this software is subject to the terms of the Autodesk license
  6. // agreement provided at the time of installation or download, or which
  7. // otherwise accompanies this software in either electronic or hard copy form.
  8. //
  9. //////////////////////////////////////////////////////////////////////////////
  10. //-----------------------------------------------------------------------------
  11. // Directions for use:
  12. //
  13. // Derive from the AsdkPromptBase class in a separate cpp/h set. The arguments to the
  14. // template function are:
  15. //
  16. // AsdkPromptBase<WrapperInterface, &WrapperCLSID>
  17. //
  18. // e.g.:
  19. // class CEmployeePromptClass : public AsdkPromptBase<IEmployeeWrap, &CLSID_EmployeeWrap>
  20. //
  21. //
  22. // Within the child class definition, create the PROMPT_MAP. Example:
  23. //
  24. // BEGIN_PROMPT_MAP(CChildClassName)
  25. // PROMPT_ENTRY("Cube", DISPID_CUBE, RTLONG, IDS_CUBE_DEFAULT, IDS_CUBE_PROMPT_STRING, false)
  26. // PROMPT_ENTRY("Id", DISPID_ID, RTLONG, IDS_ID_DEFAULT, IDS_ID_PROMPT_STRING, false)
  27. // END_PROMPT_MAP
  28. //
  29. //
  30. // The format for the PROMPT_ENTRY is:
  31. // PROMPT_ENTRY(
  32. // L"DESCRIPTION", - String describing the entry
  33. // DISPID, - The DISPID for this property in the wrapper
  34. // PROMPT_TYPE, - The type of input expected within the command loop
  35. // DEFAULT_VALUE, - A string indicating the default (for arrays, separate by comma e.g. "10,10,10")
  36. // COMMANDLINE_PROMPT, - String to prompt the user at the commandline
  37. // JIG-ABLE_PROPERTY) - Boolean indicating whether to use an acedGetXXX() or a Jig to retrieve this property value
  38. //
  39. // PROMPT_ENTRY_INITGET(
  40. // L"DESCRIPTION", - String describing the entry
  41. // DISPID, - The DISPID for this property in the wrapper
  42. // PROMPT_TYPE, - The type of input expected within the command loop
  43. // INITGET, - Specify initget value
  44. // KEYWORDS, - A string specifying the keywords to use in initget
  45. // DEFAULT_VALUE, - A string indicating the default (for arrays, separate by comma e.g. "10,10,10")
  46. // COMMANDLINE_PROMPT, - String to prompt the user at the commandline
  47. // JIG-ABLE_PROPERTY) - Boolean indicating whether to use an acedGetXXX() or a Jig to retrieve this property value
  48. //
  49. // PROMPT_ENTRY_SYMBOL(
  50. // L"DESCRIPTION", - String describing the entry
  51. // DISPID, - The DISPID for this property in the wrapper
  52. // DEFAULT_VALUE, - A string indicating the default (for arrays, separate by comma e.g. "10,10,10")
  53. // COMMANDLINE_PROMPT, - String to prompt the user at the commandline
  54. // JIG-ABLE_PROPERTY) - Boolean indicating whether to use an acedGetXXX() or a Jig to retrieve this property value
  55. //
  56. //
  57. // PROMPTTYPE can be one of the following (defined in adscodes.h)
  58. // RTREAL, RTPOINT, RTSHORT, RTANG, RTSTR, RT3DPOINT, RTLONG, RTENAME
  59. //
  60. //
  61. // Now define the DEFINE_SAMPLER macro to specify the type of input allowed
  62. // (see AcEdJig::sampler for details)
  63. // Example:
  64. // DEFINE_SAMPLER(
  65. // AcEdJig::kCrosshair,
  66. // (UserInputControls)(kNullResponseAccepted| kAccept3dCoordinates));
  67. //
  68. // Finally, provide an implementation for GetResourceHandle(). In this function
  69. // return the resource handle where the prompt class can find string definition
  70. // defined in the prompt MAP
  71. //
  72. // virtual HINSTANCE GetResourceInstance ()
  73. //
  74. //
  75. // Instantiation:
  76. //
  77. // To use the new prompt object, create a command using ACRX_CMD_INTERRUPTIBLE
  78. // flag to support modeless operation. Instantiate the prompt child
  79. // within the command using CComObject (to implement IUnknown), and
  80. // call promptLoop():
  81. //
  82. // CComObject<CEmployeePromptClass> prompt ;
  83. // prompt.promptLoop () ;
  84. //
  85. // promptLoop() returns the AcDbObjectId of the value appended to the
  86. // database upon completion of the command. You may modify this entity
  87. // using this id as necessary after the promptLoop() has completed.
  88. //
  89. //
  90. // Customization by using the callbacks:
  91. //
  92. // Virtual callbacks are defined to allow customization beyond the MAP. They are:
  93. //
  94. // virtual void constructorCallback ()
  95. // - Called only once after initial construction.
  96. //
  97. // virtual int promptCallback (int index)
  98. // - Called in a loop to proceed with data acquisition prompt for types
  99. // which aren't supported by the AsdkPromptBase class. Or in case you want to
  100. // provide the data acquisition prompt yourself.
  101. // Returning RTINPUTTRUNCATED tells the prompt class to proceed with the MAP
  102. // definition. Returning any other value like: RTCAN / RTNORM / RTKWORD / ...
  103. // tells the prompt class that you proceeded data acquisition prompt yourself.
  104. //
  105. // virtual AcEdJig::DragStatus samplerCallback (int index, bool &compareChange)
  106. // - Called in a loop to proceed with data acquisition for types which aren't
  107. // supported by the AsdkPromptBase class. Or in case you want to provide the
  108. // data acquisition yourself.
  109. // Returning kOther tells the prompt class to proceed with the MAP
  110. // definition. Returning any other value like: kCancel / kNormal / kNoChange / ...
  111. // tells the prompt class that you proceeded data yourself.
  112. //
  113. // virtual bool updateCallback (int index)
  114. // - Called in a loop to update entity after data acquisition.
  115. // Returning false tells the prompt class to proceed with the default implementation.
  116. // Returning true means you did it yourself.
  117. //
  118. // virtual bool keywordCallback (int index, TCHAR *kword, void *value)
  119. // - Called by the framework to proceed with keywords.
  120. // Returning true tells the prompt class you proceeded the keyword and that
  121. // you might have change the 'value'
  122. //
  123. // JIG-ABLE_PROPERTY == true, kword is a AcEdJig::DragStatus* and not a string!
  124. // PROMPT_TYPE == RTREAL value is a double*
  125. // PROMPT_TYPE == RTPOINT value is an AcGePoint2d*
  126. // PROMPT_TYPE == RTSHORT <impossible>
  127. // PROMPT_TYPE == RTANG value is a double*
  128. // PROMPT_TYPE == RTSTR value is a TCHAR*
  129. // PROMPT_TYPE == RT3DPOINT value is an AcGePoint3d*
  130. // PROMPT_TYPE == RTLONG <impossible>
  131. // PROMPT_TYPE == RTENAME <impossible>
  132. //
  133. // JIG-ABLE_PROPERTY == false, kword is a TCHAR* containing the specified keyword
  134. // PROMPT_TYPE == RTREAL value is a double*
  135. // PROMPT_TYPE == RTPOINT value is an ads_point
  136. // PROMPT_TYPE == RTSHORT value is an int*
  137. // PROMPT_TYPE == RTANG value is a double*
  138. // PROMPT_TYPE == RTSTR value is a TCHAR*
  139. // PROMPT_TYPE == RT3DPOINT value is an ads_point
  140. // PROMPT_TYPE == RTLONG value is an int*
  141. // PROMPT_TYPE == RTENAME value is an ads_name
  142. //
  143. // virtual bool defaultValueCallback (int index, LPWSTR szDefaultVal)
  144. // - Called by the prompt class to let application specifying a default value.
  145. // Value is stored in the szDefaultVal parameter and must not exceed 132 characters
  146. // including the null character.
  147. // Returning false tells the prompt class to use the MAP definition. Returning true
  148. // tells the prompt class you provided a value which will be used as the default value.
  149. //
  150. //-----------------------------------------------------------------------------
  151. //-----------------------------------------------------------------------------
  152. #pragma once
  153. //-----------------------------------------------------------------------------
  154. #include <string.h>
  155. #include "dbjig.h"
  156. #include "adscodes.h"
  157. //-----------------------------------------------------------------------------
  158. #define IDR_ASDKPROMPTBASE 700
  159. //-----------------------------------------------------------------------------
  160. BOOL acedSetIUnknownForCurrentCommand (const LPUNKNOWN) ;
  161. //-----------------------------------------------------------------------------
  162. struct PROMPT_MAP_ENTRY {
  163. LPCWSTR m_szDesc ;
  164. DISPID m_dispId ;
  165. int m_promptType ;
  166. int m_cronly ;
  167. int m_nInitget ;
  168. UINT m_nKeywords ;
  169. UINT m_nDefaultValue ;
  170. UINT m_nPrompt ;
  171. bool m_bJigThisProperty ;
  172. bool m_bGotThisProperty ;
  173. VARTYPE m_paramType ;
  174. VARIANT m_vValue ;
  175. } ;
  176. //-----------------------------------------------------------------------------
  177. template <typename T, const GUID *TCLSIDWrapper>
  178. class ATL_NO_VTABLE AsdkPromptBase :
  179. public CComObjectRootEx<CComSingleThreadModel>,
  180. public CComCoClass<AsdkPromptBase<T,TCLSIDWrapper>, NULL>,
  181. public IPropertyNotifySink,
  182. public AcEdJig
  183. {
  184. protected:
  185. CComPtr<T> m_pWrapperObject ;
  186. CLSID m_CLSID_ObjectWrapper ;
  187. AcDbObject *m_pDbrObject ;
  188. DWORD m_dConnectionID ;
  189. CComQIPtr<IAcadBaseObject2> m_pBaseObj ;
  190. CComPtr<IConnectionPoint> m_pConPt ;
  191. AcDbDatabase *m_pDb ;
  192. AcApDocument *m_pDoc ;
  193. AcGePoint3d m_cursor3dPos, m_pos3d ;
  194. AcGePoint2d m_cursorPos, m_pos ;
  195. double m_cursorDist, m_dist ;
  196. double m_cursorAngle, m_angle ;
  197. TCHAR *m_szCursorString, *m_szString ;
  198. AcEdJig::CursorType m_jigCursorType ;
  199. AcEdJig::UserInputControls m_jigUserInputControls ;
  200. volatile LONG m_cRef ;
  201. protected:
  202. AsdkPromptBase () : AcEdJig (),
  203. m_cursor3dPos(), m_pos3d(), m_cursorPos(), m_pos(),
  204. m_cursorDist(0), m_dist(0), m_cursorAngle(0), m_angle(0),
  205. m_szCursorString(NULL), m_szString(NULL)
  206. {
  207. //- Assigned here because CLSID_ObjectWrapper is used outside the class definition
  208. //- in the macro defined for the child class constructor...
  209. m_CLSID_ObjectWrapper =*TCLSIDWrapper ;
  210. }
  211. virtual ~AsdkPromptBase () {}
  212. DECLARE_REGISTRY_RESOURCEID(IDR_ASDKPROMPTBASE)
  213. DECLARE_PROTECT_FINAL_CONSTRUCT()
  214. BEGIN_COM_MAP(AsdkPromptBase)
  215. COM_INTERFACE_ENTRY(IPropertyNotifySink)
  216. END_COM_MAP()
  217. HRESULT FinalConstruct () { return (S_OK) ; }
  218. void FinalRelease () {}
  219. virtual HINSTANCE GetResourceInstance () =0 ;
  220. void SetDocument (AcApDocument *pDoc) { m_pDoc =pDoc ; }
  221. //- Prompt MAP
  222. int GetPromptMapSize () {
  223. PROMPT_MAP_ENTRY *pPromptMap =GetPromptMap () ;
  224. int i =0 ;
  225. while ( pPromptMap [i].m_szDesc )
  226. i++ ;
  227. return (i) ;
  228. }
  229. virtual PROMPT_MAP_ENTRY *GetPromptMap () =0 ;
  230. //- Property callbacks for custom types
  231. virtual VARTYPE propertyTypeCallback (int index, VARTYPE varType) { return (varType) ; }
  232. virtual void setProperty (int index, VARIANT &var, long val) {
  233. if ( V_VT(&var) == VT_I4 )
  234. V_I4(&var) =val ;
  235. else if ( V_VT(&var) == VT_I2 )
  236. V_I2(&var) =static_cast<short>(val) ;
  237. }
  238. virtual void setProperty (int index, VARIANT &var, short val) {
  239. if ( V_VT(&var) == VT_I4 )
  240. V_I4(&var) =static_cast<long>(val) ;
  241. else if ( V_VT(&var) == VT_I2 )
  242. V_I2(&var) =val ;
  243. }
  244. virtual void setProperty (int index, VARIANT &var, double val) {
  245. if ( V_VT(&var) == VT_R8 )
  246. V_R8(&var) =val ;
  247. else if ( V_VT(&var) == VT_R4 )
  248. V_R4(&var) =static_cast<float>(val) ;
  249. }
  250. virtual void setProperty (int index, VARIANT &var, float val) {
  251. if ( V_VT(&var) == VT_R8 )
  252. V_R8(&var) =static_cast<double>(val) ;
  253. else if ( V_VT(&var) == VT_R4 )
  254. V_R4(&var) =val ;
  255. }
  256. virtual void setProperty (int index, VARIANT &var, TCHAR *val) {
  257. V_BSTR(&var) =_bstr_t (val).copy () ;
  258. }
  259. virtual void setProperty (int index, VARIANT &var, AcGePoint3d &val) {
  260. AcAxPoint3d pt (val) ;
  261. pt.setVariant (var) ; //- VT_ARRAY | VT_R8
  262. }
  263. virtual void setProperty (int index, VARIANT &var, AcGePoint2d &val) {
  264. AcAxPoint2d pt (val) ;
  265. pt.setVariant (var) ; //- VT_ARRAY | VT_R8
  266. }
  267. //- Property - COM
  268. HRESULT GetPropertyTypeInfo () {
  269. //- This function will grep the wrapper's type library to obtain the property type information for each DISPID we place in the map. It
  270. //- will use this information to pass the values we jig to and from the wrapper. This function is called only once during construction, before
  271. PROMPT_MAP_ENTRY *pPromptMap =GetPromptMap () ;
  272. //- Find out if we have Type Info (we should have)
  273. unsigned int count =0 ;
  274. if ( !SUCCEEDED(m_pWrapperObject->GetTypeInfoCount (&count)) )
  275. return (E_FAIL) ;
  276. //- If no Type Info, exit
  277. if ( !count )
  278. return (E_FAIL) ; //- No properties to Jig ???
  279. //- Get iTypeInfo interface for object for any locale
  280. CComPtr<ITypeInfo> pTypeInfo ;
  281. if ( !SUCCEEDED (m_pWrapperObject->GetTypeInfo (0, NULL, &pTypeInfo)) )
  282. return (E_FAIL) ;
  283. //- Retrieve type attributes - to find number of methods for entity
  284. TYPEATTR *pTypeAttr ;
  285. if ( !SUCCEEDED (pTypeInfo->GetTypeAttr (&pTypeAttr)) )
  286. return (E_FAIL) ;
  287. int numFuncs =pTypeAttr->cFuncs ;
  288. pTypeInfo->ReleaseTypeAttr (pTypeAttr) ;
  289. //- Iterate over all methods.
  290. for ( int i =0 ; i < numFuncs ; i++ ) {
  291. //- Get the function description
  292. FUNCDESC *pFuncDesc ;
  293. if ( !SUCCEEDED (pTypeInfo->GetFuncDesc (i, &pFuncDesc)) )
  294. return (E_FAIL) ;
  295. //- Get the member ID
  296. MEMBERID memberID ;
  297. memberID =pFuncDesc->memid ;
  298. int ii =0 ;
  299. for ( int ii =0 ; ii < GetPromptMapSize () ; ii++ ) {
  300. if ( memberID == pPromptMap [ii].m_dispId ) {
  301. UINT nNamesArraySize =pFuncDesc->cParams + 1, nReturnedNames ;
  302. BSTR *pBstrNames =new BSTR [nNamesArraySize] ;
  303. if ( !SUCCEEDED (pTypeInfo->GetNames (memberID, pBstrNames, nNamesArraySize, &nReturnedNames)) )
  304. return (E_FAIL) ;
  305. delete [] pBstrNames ;
  306. if ( nReturnedNames < 1 )
  307. continue ;
  308. //- Since the DISPID will be shared by both 'put' and 'get' functions, we will enter here twice for each property, though we
  309. //- only need to use one. The 'get' version will have the VT_BYREF or'ed in the VARTYPE,
  310. //- so we can chose to ignore this one to get the true type from the property 'put' version.
  311. if ( pFuncDesc->invkind == INVOKE_PROPERTYGET )
  312. continue ;
  313. //- This is equivalent to checking invkind...
  314. //if ( pFuncDesc->lprgelemdescParam [nReturnedNames - 1].tdesc.vt & VT_BYREF )
  315. // continue ;
  316. //- For properties, we assume a single argument, which means we should expect two names in this list, the property name
  317. //- and the single parameter. However, MIDL will many times lop off the name, which means we should just assume the parameter
  318. //- type is the last in this list, hence nReturnedNames-1.
  319. //pPromptMap [ii].m_paramType =pFuncDesc->lprgelemdescParam [nReturnedNames - 1].tdesc.vt ;
  320. pPromptMap [ii].m_paramType =propertyTypeCallback (ii, pFuncDesc->lprgelemdescParam [nReturnedNames - 1].tdesc.vt) ;
  321. }
  322. }
  323. }
  324. return (S_OK) ;
  325. }
  326. HRESULT PutProperty (int index) {
  327. static bool bDontLoop =false ;
  328. WORD wflags =DISPATCH_PROPERTYPUT ;
  329. DISPID putid =DISPID_PROPERTYPUT ;
  330. CComPtr<IDispatch> pDisp ;
  331. m_pWrapperObject.QueryInterface (&pDisp) ;
  332. PROMPT_MAP_ENTRY *pPromptMap =GetPromptMap () ;
  333. //- Careful acedGetPoint() and acquirePoint() returns point is UCS
  334. //- Usually COM wrapper properties are set to work in WCS
  335. //- Therefore we need to convert coordiantes from UCS to WCS
  336. //switch ( pPromptMap [index].m_promptType ) {
  337. // case RTPOINT: {
  338. // AcAxPoint2d pt (pPromptMap [index].m_vValue) ;
  339. // AcGePoint3d pt3d (pt.x, pt.y, 0) ;
  340. // acdbUcs2Wcs (asDblArray (pt3d), asDblArray (pt3d), false) ;
  341. // pt =pt3d.convert2d (AcGePlane ()) ;
  342. // pt.setVariant (pPromptMap [index].m_vValue) ;
  343. // break ;
  344. // }
  345. // case RT3DPOINT: {
  346. // AcAxPoint3d pt (pPromptMap [index].m_vValue) ;
  347. // acdbUcs2Wcs (asDblArray (pt), asDblArray (pt), false) ;
  348. // pt.setVariant (pPromptMap [index].m_vValue) ;
  349. // break ;
  350. // }
  351. //}
  352. DISPPARAMS dispparams ;
  353. dispparams.rgvarg =&pPromptMap [index].m_vValue ;
  354. dispparams.rgdispidNamedArgs =&putid ;
  355. dispparams.cArgs =1 ;
  356. dispparams.cNamedArgs =1 ;
  357. HRESULT hr=pDisp->Invoke (
  358. pPromptMap [index].m_dispId, IID_NULL, LOCALE_USER_DEFAULT,
  359. wflags, &dispparams, NULL, NULL, NULL
  360. ) ;
  361. if ( hr != S_OK && !bDontLoop ) {
  362. bDontLoop =true ;
  363. setPropertyDefault (index) ;
  364. bDontLoop =false ;
  365. }
  366. return (hr) ;
  367. }
  368. //- Property events
  369. STDMETHODIMP OnChanged (DISPID dispId) {
  370. PROMPT_MAP_ENTRY *pPromptMap=GetPromptMap () ;
  371. int i =0 ;
  372. while ( pPromptMap [i].m_szDesc ) {
  373. if ( dispId == pPromptMap [i].m_dispId ) {
  374. pPromptMap [i].m_bGotThisProperty =true ;
  375. break ;
  376. }
  377. i++ ;
  378. }
  379. if ( m_pDoc != NULL )
  380. acDocManager->sendModelessInterrupt (m_pDoc) ;
  381. return (S_OK) ;
  382. }
  383. STDMETHODIMP OnRequestEdit (DISPID dispID) { return (S_OK) ; }
  384. //- Property
  385. virtual void setPropertyDefaults (int index =-1) {
  386. PROMPT_MAP_ENTRY *pPromptMap =GetPromptMap () ;
  387. if ( index == -1) {
  388. for ( int i =0 ; pPromptMap [i].m_szDesc ; i++ )
  389. setPropertyDefault (i) ;
  390. } else {
  391. setPropertyDefault (index) ;
  392. }
  393. }
  394. void setPropertyDefault (int i) {
  395. PROMPT_MAP_ENTRY *pPromptMap =GetPromptMap () ;
  396. pPromptMap [i].m_vValue.vt =pPromptMap [i].m_paramType ;
  397. TCHAR szDefaultValue [256] ;
  398. if ( defaultValueCallback (i, szDefaultValue) == false )
  399. LoadString (pPromptMap [i].m_nDefaultValue, szDefaultValue) ;
  400. switch ( pPromptMap [i].m_paramType ) {
  401. case VT_I4:
  402. //pPromptMap [i].m_vValue.lVal =_ttol (szDefaultValue) ;
  403. setProperty (i, pPromptMap [i].m_vValue, _ttol (szDefaultValue)) ;
  404. break;
  405. case VT_I2:
  406. //pPromptMap [i].m_vValue.iVal =static_cast<short>(_ttoi (szDefaultValue)) ;
  407. setProperty (i, pPromptMap [i].m_vValue, static_cast<short>(_ttoi (szDefaultValue))) ;
  408. break;
  409. case VT_ARRAY | VT_R8: {
  410. TCHAR seps [] =L" ," ;
  411. TCHAR szDefault [MAX_PATH] ;
  412. wcscpy (szDefault, szDefaultValue) ;
  413. AcGePoint3d defPt ;
  414. TCHAR *token =wcstok (szDefault, seps) ;
  415. for ( long index =0 ; token ; index++ ) {
  416. if ( index < 3 )
  417. defPt [index] =_tstof (token) ;
  418. token =wcstok (NULL, seps) ;
  419. }
  420. //AcAxPoint3d pt (defPt) ;
  421. //pt.setVariant (pPromptMap [i].m_vValue) ;
  422. setProperty (i, pPromptMap [i].m_vValue, defPt) ;
  423. break ;
  424. }
  425. case VT_BSTR:
  426. //pPromptMap [i].m_vValue.bstrVal =_bstr_t (szDefaultValue).copy () ;
  427. setProperty (i, pPromptMap [i].m_vValue, szDefaultValue) ;
  428. break ;
  429. case VT_R8:
  430. //pPromptMap [i].m_vValue.dblVal =_tstof (szDefaultValue) ;
  431. setProperty (i, pPromptMap [i].m_vValue, _tstof (szDefaultValue)) ;
  432. break ;
  433. case VT_R4:
  434. //pPromptMap [i].m_vValue.fltVal =static_cast<float>(_tstof (szDefaultValue)) ;
  435. setProperty (i, pPromptMap [i].m_vValue, static_cast<float>(_tstof (szDefaultValue))) ;
  436. break ;
  437. }
  438. if ( pPromptMap [i].m_dispId )
  439. PutProperty (i) ;
  440. pPromptMap [i].m_bGotThisProperty =false ;
  441. }
  442. //- AcEdJig
  443. virtual void initSampler () =0 ;
  444. virtual AcEdJig::DragStatus sampler () {
  445. setSpecialCursorType (m_jigCursorType) ;
  446. setUserInputControls (m_jigUserInputControls) ;
  447. AcEdJig::DragStatus stat =AcEdJig::kCancel ;
  448. PROMPT_MAP_ENTRY *pPromptMap =GetPromptMap () ;
  449. int i =0 ;
  450. while ( pPromptMap [i].m_szDesc ) {
  451. if ( pPromptMap [i].m_bJigThisProperty && !pPromptMap [i].m_bGotThisProperty ) {
  452. bool compareChange =false ;
  453. if ( pPromptMap [i].m_nKeywords != 0 ) {
  454. TCHAR szKeywords [256] ;
  455. LoadString (pPromptMap [i].m_nKeywords, szKeywords) ;
  456. setKeywordList (szKeywords) ;
  457. }
  458. stat =samplerCallback (i, compareChange) ;
  459. if ( stat >= AcEdJig::kKW1 )
  460. keywordCallback (i, (TCHAR *)&stat, NULL) ;
  461. if ( stat == AcEdJig::kOther ) {
  462. switch ( pPromptMap [i].m_promptType ) {
  463. case RTPOINT: {
  464. AcGePoint3d pos ;
  465. stat =acquirePoint (pos) ;
  466. m_cursorPos.x =pos.x ;
  467. m_cursorPos.y =pos.y ;
  468. if ( stat >= AcEdJig::kKW1 )
  469. keywordCallback (i, (TCHAR *)&stat, &m_pos) ;
  470. compareChange =(m_cursorPos.isEqualTo (m_pos) ? true : false) ;
  471. break ;
  472. }
  473. case RT3DPOINT:
  474. stat =acquirePoint (m_cursor3dPos) ;
  475. if ( stat >= AcEdJig::kKW1 )
  476. keywordCallback (i, (TCHAR *)&stat, &m_cursor3dPos) ;
  477. compareChange =(m_cursor3dPos.isEqualTo (m_pos3d) ? true : false) ;
  478. break ;
  479. case RTREAL:
  480. stat =acquireDist (m_cursorDist) ;
  481. if ( stat >= AcEdJig::kKW1 )
  482. keywordCallback (i, (TCHAR *)&stat, &m_cursorDist) ;
  483. compareChange =(m_cursorDist != m_dist) ;
  484. break ;
  485. case RTANG:
  486. stat =acquireAngle (m_cursorAngle) ;
  487. if ( stat >= AcEdJig::kKW1 )
  488. keywordCallback (i, (TCHAR *)&stat, &m_cursorAngle) ;
  489. compareChange =(m_cursorAngle != m_angle) ;
  490. break ;
  491. case RTSTR:
  492. stat =acquireString (m_szCursorString) ;
  493. if ( stat >= AcEdJig::kKW1 )
  494. keywordCallback (i, (TCHAR *)&stat, &m_szCursorString) ;
  495. compareChange =(m_szCursorString != m_szString) ;
  496. break ;
  497. }
  498. if ( stat == AcEdJig::kNull )
  499. pPromptMap [i].m_bGotThisProperty =true ;
  500. }
  501. if ( stat == AcEdJig::kCancel )
  502. return (stat) ;
  503. if ( !compareChange ) {
  504. //RXTRACE ("AsdkPromptBase::sampler - !compareChange, stat = %d\n", stat) ;
  505. return (stat == AcEdJig::kNull ? stat : AcEdJig::kNoChange) ;
  506. } else {
  507. m_pos =m_cursorPos ;
  508. m_pos3d =m_cursor3dPos ;
  509. m_dist =m_cursorDist ;
  510. m_angle =m_cursorAngle ;
  511. m_szString =m_szCursorString ;
  512. //RXTRACE ("AsdkPromptBase::sampler - stat = %d\n", stat) ;
  513. return (stat) ;
  514. }
  515. }
  516. i++ ;
  517. }
  518. return (stat) ;
  519. }
  520. virtual AcDbEntity *entity () const {
  521. if ( m_pDbrObject == NULL )
  522. m_pBaseObj->GetObject ((AcDbObject *&)m_pDbrObject) ;
  523. return ((AcDbEntity *)m_pDbrObject) ;
  524. }
  525. virtual Adesk::Boolean update () {
  526. PROMPT_MAP_ENTRY *pPromptMap =GetPromptMap () ;
  527. for ( int i =0 ; pPromptMap [i].m_szDesc ; i++ ) {
  528. if ( pPromptMap [i].m_bJigThisProperty && !pPromptMap [i].m_bGotThisProperty ) {
  529. if ( updateCallback (i) == false ) {
  530. switch ( pPromptMap [i].m_promptType ) {
  531. case RTPOINT: {
  532. //AcAxPoint2d pt (m_cursorPos) ;
  533. //pt.setVariant (pPromptMap [i].m_vValue) ;
  534. setProperty (i, pPromptMap [i].m_vValue, m_cursorPos) ;
  535. break ;
  536. }
  537. case RT3DPOINT: {
  538. //AcAxPoint3d pt (m_cursor3dPos) ;
  539. //pt.setVariant (pPromptMap [i].m_vValue) ;
  540. setProperty (i, pPromptMap [i].m_vValue, m_cursor3dPos) ;
  541. break ;
  542. }
  543. case RTREAL:
  544. //pPromptMap [i].m_vValue.dblVal =m_cursorDist ;
  545. setProperty (i, pPromptMap [i].m_vValue, m_cursorDist) ;
  546. break ;
  547. case RTANG:
  548. //pPromptMap [i].m_vValue.dblVal =m_cursorAngle ;
  549. setProperty (i, pPromptMap [i].m_vValue, m_cursorAngle) ;
  550. break ;
  551. case RTSTR:
  552. //pPromptMap [i].m_vValue.bstrVal =_bstr_t (m_szCursorString) ;
  553. setProperty (i, pPromptMap [i].m_vValue, m_szCursorString) ;
  554. break ;
  555. default:
  556. acutPrintf (L"Type %s not handled by Jig mechanism!\n", pPromptMap [i].m_szDesc) ;
  557. break ;
  558. }
  559. PutProperty (i) ;
  560. pPromptMap [i].m_bGotThisProperty =false ;
  561. break ;
  562. }
  563. }
  564. }
  565. return (Adesk::kTrue) ;
  566. }
  567. //- Callbacks
  568. virtual void constructorCallback () {}
  569. virtual int promptCallback (int index) { return (RTINPUTTRUNCATED) ; } //- Return RTCAN to cancel the prompt. Return RTNORM to prevent the MAP entry
  570. virtual AcEdJig::DragStatus samplerCallback (int index, bool &compareChange) { return (kOther) ; } //- Return different value to skip the MAP entry
  571. virtual bool updateCallback (int index) { return (false) ; } //- Return true to skip the MAP entry
  572. virtual bool keywordCallback (int index, TCHAR *kword, void *value) { return (false) ; }
  573. virtual bool defaultValueCallback (int index, LPWSTR szDefaultVal) { return (false) ; }
  574. //- Utility
  575. int LoadString (UINT uID, LPWSTR szString, int nBufferMax =255) {
  576. int ret =0 ;
  577. *szString =L'\0' ;
  578. if ( uID != 0 && uID != (UINT)-1 )
  579. ret =::LoadString (GetResourceInstance (), uID, szString, nBufferMax) ;
  580. return (ret) ;
  581. }
  582. LPCWSTR BuildPromptString (int index) {
  583. PROMPT_MAP_ENTRY *pPromptMap =GetPromptMap () ;
  584. static TCHAR szPrompt [256] ;
  585. LoadString (pPromptMap [index].m_nPrompt, szPrompt) ;
  586. TCHAR szDefaultVal [256] ;
  587. *szDefaultVal =L'\0' ;
  588. if ( defaultValueCallback (index, szDefaultVal) == false )
  589. LoadString (pPromptMap [index].m_nDefaultValue, szDefaultVal) ;
  590. if ( *szDefaultVal != L'\0' ) {
  591. wcscat (szPrompt, L" <") ;
  592. wcscat (szPrompt, szDefaultVal) ;
  593. wcscat (szPrompt, L">") ;
  594. }
  595. wcscat (szPrompt, L": ") ;
  596. return (szPrompt) ;
  597. }
  598. public:
  599. virtual AcDbObjectId promptLoop () {
  600. setPropertyDefaults (-1) ;
  601. //- The szDefaultValue member of the map may need to be altered to reflect
  602. //- the desired default values. We need to check these, and populate the variant in each
  603. //- map entry with these values each time we run the loop.
  604. DragStatus stat =kNormal ;
  605. int retval =RTNORM ;
  606. PROMPT_MAP_ENTRY *pPromptMap =GetPromptMap () ;
  607. int i =0 ;
  608. while ( true ) {
  609. bool done =true ;
  610. while ( pPromptMap [i].m_szDesc ) {
  611. if ( !pPromptMap [i].m_bJigThisProperty && !pPromptMap [i].m_bGotThisProperty ) {
  612. done =false ;
  613. retval =promptCallback (i) ;
  614. if ( retval == RTCAN )
  615. break ;
  616. if ( retval == RTINPUTTRUNCATED ) { //- return RTINPUTTRUNCATED to use the defaults
  617. TCHAR szKeyword [133] ;
  618. if ( pPromptMap [i].m_nKeywords != 0 ) {
  619. LoadString (pPromptMap [i].m_nKeywords, szKeyword, 132) ;
  620. acedInitGet (pPromptMap [i].m_nInitget, szKeyword) ;
  621. }
  622. LPCWSTR szPrompt =BuildPromptString (i) ;
  623. switch ( pPromptMap [i].m_promptType ) {
  624. case RTPOINT: {
  625. ads_point point ;
  626. retval =acedGetPoint (NULL, szPrompt, point) ;
  627. if ( retval == RTKWORD ) {
  628. acedGetInput (szKeyword) ;
  629. if ( keywordCallback (i, szKeyword, point) == true )
  630. retval =RTNORM ;
  631. }
  632. if ( retval == RTNORM ) {
  633. AcGePoint2d pt2d (point [X], point [Y]) ;
  634. //AcAxPoint2d vPt (pt2d) ;
  635. //vPt.setVariant (pPromptMap [i].m_vValue) ;
  636. setProperty (i, pPromptMap [i].m_vValue, pt2d) ;
  637. PutProperty (i) ;
  638. }
  639. break ;
  640. }
  641. case RT3DPOINT: {
  642. ads_point point ;
  643. retval =acedGetPoint (NULL, szPrompt, point) ;
  644. if ( retval == RTKWORD ) {
  645. acedGetInput (szKeyword) ;
  646. if ( keywordCallback (i, szKeyword, point) == true )
  647. retval =RTNORM ;
  648. }
  649. if ( retval == RTNORM ) {
  650. AcGePoint3d pt3d (point [0], point [1], point [2]) ;
  651. //AcAxPoint3d vPt (pt3d) ;
  652. //vPt.setVariant (pPromptMap [i].m_vValue) ;
  653. setProperty (i, pPromptMap [i].m_vValue, pt3d) ;
  654. PutProperty (i) ;
  655. }
  656. break ;
  657. }
  658. case RTREAL: {
  659. double dist =0 ;
  660. retval =acedGetReal (szPrompt, &dist) ;
  661. if ( retval == RTKWORD ) {
  662. acedGetInput (szKeyword) ;
  663. if ( keywordCallback (i, szKeyword, &dist) == true )
  664. retval =RTNORM ;
  665. }
  666. if ( retval == RTNORM ) {
  667. //pPromptMap [i].m_vValue.dblVal =dist ;
  668. setProperty (i, pPromptMap [i].m_vValue, dist) ;
  669. PutProperty (i) ;
  670. }
  671. break ;
  672. }
  673. case RTANG: {
  674. double angle =0 ;
  675. retval =acedGetAngle (NULL, szPrompt, &angle) ;
  676. if ( retval == RTKWORD ) {
  677. acedGetInput (szKeyword) ;
  678. if ( keywordCallback (i, szKeyword, &angle) == true )
  679. retval =RTNORM ;
  680. }
  681. if ( retval == RTNORM ) {
  682. //pPromptMap [i].m_vValue.dblVal =angle ;
  683. setProperty (i, pPromptMap [i].m_vValue, angle) ;
  684. PutProperty (i) ;
  685. }
  686. break ;
  687. }
  688. case RTSTR: {
  689. TCHAR szBuffer [132] ;
  690. *szBuffer =L'\0' ;
  691. retval =acedGetString (pPromptMap [i].m_cronly, szPrompt, szBuffer) ;
  692. if ( retval == RTKWORD ) {
  693. acedGetInput (szKeyword) ;
  694. if ( keywordCallback (i, szKeyword, szBuffer) == true )
  695. retval =RTNORM ;
  696. }
  697. if ( retval == RTNORM ) {
  698. if ( wcslen (szBuffer) ) //- No zero length strings...
  699. //pPromptMap [i].m_vValue.bstrVal =_bstr_t (szBuffer) ;
  700. setProperty (i, pPromptMap [i].m_vValue, szBuffer) ;
  701. PutProperty (i) ;
  702. }
  703. break ;
  704. }
  705. case RTLONG: {
  706. int _int =0 ;
  707. retval =acedGetInt (szPrompt, &_int) ;
  708. if ( retval == RTKWORD ) {
  709. acedGetInput (szKeyword) ;
  710. if ( keywordCallback (i, szKeyword, &_int) == true )
  711. retval =RTNORM ;
  712. }
  713. if ( retval == RTNORM ) {
  714. //pPromptMap [i].m_vValue.lVal =static_cast<LONG>(_int) ;
  715. setProperty (i, pPromptMap [i].m_vValue, static_cast<long>(_int)) ;
  716. PutProperty (i) ;
  717. }
  718. break ;
  719. }
  720. case RTSHORT: {
  721. int _int =0 ;
  722. retval =acedGetInt (szPrompt, &_int) ;
  723. if ( retval == RTKWORD ) {
  724. acedGetInput (szKeyword) ;
  725. if ( keywordCallback (i, szKeyword, &_int) == true )
  726. retval =RTNORM ;
  727. }
  728. if ( retval == RTNORM ) {
  729. //pPromptMap [i].m_vValue.iVal =static_cast<SHORT>(_int) ;
  730. setProperty (i, pPromptMap [i].m_vValue, static_cast<short>(_int)) ;
  731. PutProperty (i) ;
  732. }
  733. break ;
  734. }
  735. case RTENAME: {
  736. ads_name ename ;
  737. ads_point pt ;
  738. retval =acedEntSel (szPrompt, ename, pt) ;
  739. if ( retval == RTKWORD ) {
  740. acedGetInput (szKeyword) ;
  741. if ( keywordCallback (i, szKeyword, ename) == true )
  742. retval =RTNORM ;
  743. }
  744. if ( retval == RTNORM ) {
  745. //pPromptMap [i].m_vValue.lVal =static_cast<LONG>(ename [0]) ;
  746. setProperty (i, pPromptMap [i].m_vValue, static_cast<long>(ename [0])) ;
  747. PutProperty (i) ;
  748. }
  749. break ;
  750. }
  751. }
  752. }
  753. if ( retval == RTNONE )
  754. pPromptMap [i].m_bGotThisProperty =true ;
  755. if ( retval == RTCAN ) {
  756. done =true ;
  757. break ;
  758. }
  759. if ( pPromptMap [i].m_bGotThisProperty == true )
  760. i++ ;
  761. } else {
  762. i++ ;
  763. }
  764. }
  765. if ( done )
  766. break ;
  767. else
  768. i =0 ;
  769. }
  770. if ( retval == RTCAN )
  771. return (AcDbObjectId::kNull) ;
  772. i =0 ;
  773. while ( true ) {
  774. bool done =true ;
  775. while( pPromptMap [i].m_szDesc ) {
  776. if ( pPromptMap [i].m_bJigThisProperty && !pPromptMap [i].m_bGotThisProperty ) {
  777. done =false ;
  778. retval =promptCallback (i) ;
  779. if ( retval == RTINPUTTRUNCATED ) {
  780. setDispPrompt (BuildPromptString (i)) ;
  781. stat =drag () ;
  782. if ( stat == AcEdJig::kNormal ) {
  783. switch ( pPromptMap [i].m_promptType ) {
  784. case RTPOINT: {
  785. //AcAxPoint2d pos (m_cursorPos) ;
  786. //pos.setVariant (pPromptMap [i].m_vValue) ;
  787. setProperty (i, pPromptMap [i].m_vValue, m_cursorPos) ;
  788. PutProperty (i) ;
  789. break ;
  790. }
  791. case RT3DPOINT: {
  792. //AcAxPoint3d pos (m_cursor3dPos) ;
  793. //pos.setVariant (pPromptMap [i].m_vValue) ;
  794. setProperty (i, pPromptMap [i].m_vValue, m_cursor3dPos) ;
  795. PutProperty (i) ;
  796. break ;
  797. }
  798. case RTREAL:
  799. //pPromptMap [i].m_vValue.dblVal =m_cursorDist ;
  800. setProperty (i, pPromptMap [i].m_vValue, m_cursorDist) ;
  801. PutProperty (i) ;
  802. break ;
  803. case RTANG:
  804. //pPromptMap [i].m_vValue.dblVal =m_cursorAngle ;
  805. setProperty (i, pPromptMap [i].m_vValue, m_cursorAngle) ;
  806. PutProperty (i) ;
  807. break ;
  808. case RTSTR:
  809. //pPromptMap [i].m_vValue.bstrVal =_bstr_t (m_szCursorString) ;
  810. setProperty (i, pPromptMap [i].m_vValue, m_szCursorString) ;
  811. PutProperty (i) ;
  812. break ;
  813. }
  814. }
  815. if ( stat == AcEdJig::kCancel ) {
  816. done =true ;
  817. break ;
  818. }
  819. }
  820. if ( retval == RTCAN || retval == AcEdJig::kCancel ) {
  821. stat =AcEdJig::kCancel ;
  822. done =true ;
  823. break ;
  824. }
  825. if ( pPromptMap [i].m_bGotThisProperty == true )
  826. i++ ;
  827. } else {
  828. i++ ;
  829. }
  830. }
  831. if ( done )
  832. break ;
  833. else
  834. i =0 ;
  835. }
  836. if ( stat != AcEdJig::kCancel ) {
  837. if ( m_pBaseObj )
  838. m_pBaseObj->GetObject (m_pDbrObject) ;
  839. return (append ()) ;
  840. }
  841. return (AcDbObjectId::kNull) ;
  842. }
  843. } ;
  844. //-----------------------------------------------------------------------------
  845. #define BEGIN_PROMPT_MAP(CLASSNAME) \
  846. public: \
  847. CLASSNAME () { \
  848. HRESULT hr =S_OK ; \
  849. if ( FAILED(hr =m_pWrapperObject.CoCreateInstance (m_CLSID_ObjectWrapper)) ) { \
  850. acutPrintf (L"Unable to Create Wrapper Class\n") ; \
  851. throw hr ; \
  852. } \
  853. m_pBaseObj =m_pWrapperObject ; \
  854. if ( FAILED (hr =m_pBaseObj->CreateObject ()) ) \
  855. throw hr ; \
  856. SetDocument (curDoc ()) ; \
  857. CComPtr<IUnknown> pUnkCmd ; \
  858. hr =QueryInterface (IID_IUnknown, (void **)&pUnkCmd) ; \
  859. if ( FAILED(hr) ) \
  860. throw hr ; \
  861. CComQIPtr<IConnectionPointContainer> pPtContainer ; \
  862. pPtContainer =m_pWrapperObject ; \
  863. hr =pPtContainer->FindConnectionPoint (IID_IPropertyNotifySink, &m_pConPt) ; \
  864. if ( FAILED(hr) ) \
  865. throw hr ; \
  866. \
  867. if ( FAILED(hr =GetPropertyTypeInfo ()) ) { \
  868. acutPrintf (L"Unable to Obtain Correct Type Information from the Wrapper Class\n") ; \
  869. throw hr ; \
  870. } \
  871. if ( FAILED(hr =m_pConPt->Advise (pUnkCmd, &m_dConnectionID)) ) \
  872. throw hr ; \
  873. \
  874. BOOL bRet =acedSetIUnknownForCurrentCommand (m_pWrapperObject) ; \
  875. m_pDb =acdbHostApplicationServices ()->workingDatabase () ; \
  876. \
  877. AcDbObject *pObj =NULL ; \
  878. m_pBaseObj->GetObject (pObj) ; \
  879. m_pDbrObject =pObj ; \
  880. AcDbEntity *pEnt=(AcDbEntity *)AcDbEntity::cast (pObj) ; \
  881. if ( pEnt ) \
  882. pEnt->setDatabaseDefaults () ; \
  883. m_pBaseObj->SetObject (pObj) ; \
  884. constructorCallback () ; \
  885. initSampler () ; \
  886. } \
  887. ~CLASSNAME () { \
  888. m_pConPt->Unadvise (m_dConnectionID) ; \
  889. if ( m_pBaseObj ) \
  890. m_pBaseObj->GetObject (m_pDbrObject) ; \
  891. } \
  892. HRESULT STDMETHODCALLTYPE QueryInterface (REFIID refiid, void **ppv) { \
  893. if ( refiid == IID_IUnknown || refiid == IID_IPropertyNotifySink ) \
  894. *ppv =this ; \
  895. else \
  896. return (E_NOINTERFACE) ; \
  897. static_cast<IUnknown *>(this)->AddRef () ; \
  898. return (S_OK) ; \
  899. } \
  900. ULONG STDMETHODCALLTYPE AddRef () { \
  901. return (InterlockedIncrement (&m_cRef)) ; \
  902. } \
  903. ULONG STDMETHODCALLTYPE Release () { \
  904. ULONG ul =InterlockedDecrement (&m_cRef) ; \
  905. return (ul) ; \
  906. } \
  907. virtual PROMPT_MAP_ENTRY* GetPromptMap () { \
  908. static PROMPT_MAP_ENTRY pPromptMap [] = {
  909. //-----------------------------------------------------------------------------
  910. #define PROMPT_ENTRY(szDesc,dispId,promptType,defaultValueId,promptId,bJigThisProperty) \
  911. { szDesc, dispId, promptType, 1, 0, 0, defaultValueId, promptId, bJigThisProperty },
  912. #define PROMPT_ENTRY_INITGET(szDesc,dispId,promptType,initget,keywordsId,defaultValueId,promptId,bJigThisProperty) \
  913. { szDesc, dispId, promptType, 1, initget, keywordsId, defaultValueId, promptId, bJigThisProperty },
  914. #define PROMPT_ENTRY_SYMBOL(szDesc,dispId,defaultValueId,promptId,bJigThisProperty) \
  915. { szDesc, dispId, RTSTR, 0, 0, 0, defaultValueId, promptId, bJigThisProperty },
  916. //-----------------------------------------------------------------------------
  917. #define END_PROMPT_MAP \
  918. { NULL, 0, 0, 0, 0, 0, 0, false, false, VT_EMPTY } \
  919. } ; \
  920. return (pPromptMap) ; \
  921. }
  922. //-----------------------------------------------------------------------------
  923. #define DEFINE_SAMPLER(CURSORTYPE,USERINPUTCONTROLS) \
  924. virtual void initSampler () { \
  925. m_jigCursorType =CURSORTYPE ; \
  926. m_jigUserInputControls =USERINPUTCONTROLS ; \
  927. }