libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cmGrPage.c 36KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471
  1. #include "cmGlobal.h"
  2. #include "cmFloatTypes.h"
  3. #include "cmRpt.h"
  4. #include "cmErr.h"
  5. #include "cmCtx.h"
  6. #include "cmErr.h"
  7. #include "cmMem.h"
  8. #include "cmMallocDebug.h"
  9. #include "cmGr.h"
  10. #include "cmGrDevCtx.h"
  11. #include "cmGrPlot.h"
  12. #include "cmGrPage.h"
  13. #include "cmVectOpsTemplateMain.h"
  14. enum
  15. {
  16. kHashLength = 6,
  17. kHashCharCnt = 10,
  18. kMaxHashCnt = 10
  19. };
  20. enum
  21. {
  22. kNotValidFl = 0x01,
  23. kDirtyFl = 0x02, // set if the layout is dirty
  24. kFocusFl = 0x04
  25. };
  26. typedef struct
  27. {
  28. cmGrPPt_t xy0; //
  29. cmGrPPt_t xy1; // xy1 is on iext
  30. } cmGrPgHash_t;
  31. struct cmGrPgVw_str;
  32. struct cmGrPgAxis_str;
  33. struct cmGrPg_str;
  34. typedef struct cmGrPgLabelFunc_str
  35. {
  36. unsigned id;
  37. cmGrLabelFunc_t func;
  38. void* arg;
  39. cmChar_t* label;
  40. struct cmGrPgLabelFunc_str* link;
  41. } cmGrPgLabelFunc_t;
  42. typedef struct cmGrPgAxis_str
  43. {
  44. struct cmGrPgVw_str* vp;
  45. unsigned flags; // kHashMarkGrFl | kHashLabelGrFl
  46. unsigned hashCnt;
  47. unsigned hashLength;
  48. cmChar_t* title;
  49. cmGrPgHash_t* hash;
  50. unsigned maxHashCnt;
  51. cmGrPPt_t titlePt; // position of the axis title
  52. unsigned titleFontId; // title font id
  53. unsigned titleFontStyle; // title font style
  54. unsigned titleFontSize; // title font size
  55. cmGrPPt_t labelPt; // x = l/r label pos. and y=t/b label pos.
  56. unsigned labelFontId; // label font id
  57. unsigned labelFontStyle; // label font style
  58. unsigned labelFontSize; // label font size
  59. cmGrPgLabelFunc_t* func;
  60. } cmGrPgAxis_t;
  61. typedef struct cmGrPgVw_str
  62. {
  63. struct cmGrPg_str* p;
  64. cmGrH_t grH;
  65. unsigned ri; // row index
  66. unsigned ci; // column index
  67. cmGrPExt_t pext; // page around outside of view
  68. cmGrPExt_t iext; // view physical extents
  69. cmGrPgAxis_t axis[ kAxisGrCnt ]; //
  70. cmGrPPt_t titlePt; // lower/center position of the view title
  71. cmChar_t* title; // view title (upper center)
  72. unsigned fontId; // title font id
  73. unsigned fontStyle; // title font style
  74. unsigned fontSize; // title font size
  75. cmGrPgLabelFunc_t* xfunc;
  76. cmGrPgLabelFunc_t* yfunc;
  77. } cmGrPgVw_t;
  78. typedef struct cmGrPg_str
  79. {
  80. cmCtx_t ctx;
  81. cmErr_t err;
  82. cmGrCbFunc_t cbFunc;
  83. void* cbArg;
  84. unsigned flags; // kNotValidFl
  85. cmGrPExt_t pext; // outer border around all views
  86. unsigned rn; // count of rows
  87. unsigned cn; // count of columns
  88. unsigned vn; // view count (rn*cn)
  89. double* rpropV; // sum(rprop[rn]) == 1.0 pgaction of r.w() assigned to each row
  90. double* cpropV; // sum(cprop[cn]) == 1.0 pgaction of r.h() assigned to each row
  91. cmGrPgVw_t* viewV; // viewV[vn]
  92. unsigned focusIdx; // focused view index
  93. cmGrPPt_t titlePt; //
  94. cmChar_t* title; // page title
  95. unsigned fontId; // title font id
  96. unsigned fontStyle; // title font style
  97. unsigned fontSize; // title font size
  98. unsigned labelFuncId; // next page label function id
  99. cmGrPgLabelFunc_t* funcs; // linked list of value to string translation functions
  100. } cmGrPg_t;
  101. cmGrPgH_t cmGrPgNullHandle = cmSTATIC_NULL_HANDLE;
  102. cmGrVwH_t cmGrVwNullHandle = cmSTATIC_NULL_HANDLE;
  103. cmGrAxH_t cmGrAxNullHandle = cmSTATIC_NULL_HANDLE;
  104. cmGrPg_t* _cmGrPgHandleToPtr( cmGrPgH_t h )
  105. {
  106. cmGrPg_t* p = (cmGrPg_t*)h.h;
  107. assert( p!=NULL);
  108. return p;
  109. }
  110. cmGrPgVw_t* _cmGrPgVwHandleToPtr( cmGrVwH_t h )
  111. {
  112. cmGrPgVw_t* p = (cmGrPgVw_t*)h.h;
  113. assert( p!=NULL);
  114. return p;
  115. }
  116. cmGrPgAxis_t* _cmGrPgAxisHandleToPtr( cmGrAxH_t h )
  117. {
  118. cmGrPgAxis_t* p = (cmGrPgAxis_t*)h.h;
  119. assert( p!=NULL);
  120. return p;
  121. }
  122. void _cmGrPgVwAxisDestroy( cmGrPgAxis_t* ap )
  123. {
  124. ap->func = NULL;
  125. cmMemFree(ap->hash);
  126. cmMemFree(ap->title);
  127. }
  128. void _cmGrPgVwDestroy( cmGrPgVw_t* vp )
  129. {
  130. unsigned i;
  131. cmGrDestroy( &vp->grH );
  132. cmMemFree(vp->title);
  133. for(i=0; i<kAxisGrCnt; ++i)
  134. _cmGrPgVwAxisDestroy(vp->axis + i );
  135. }
  136. void _cmGrPgFinal( cmGrPg_t* p )
  137. {
  138. unsigned i;
  139. for(i=0; i<p->vn; ++i)
  140. _cmGrPgVwDestroy( p->viewV + i );
  141. cmGrPgLabelFunc_t* lfp = p->funcs;
  142. while( lfp != NULL )
  143. {
  144. cmGrPgLabelFunc_t* np = lfp->link;
  145. cmMemFree(lfp->label);
  146. cmMemFree(lfp);
  147. lfp = np;
  148. }
  149. p->funcs = NULL;
  150. cmMemFree(p->viewV);
  151. cmMemFree(p->title);
  152. cmMemFree(p->rpropV);
  153. cmMemFree(p->cpropV);
  154. }
  155. cmGrRC_t _cmGrPgDestroy( cmGrPg_t* p )
  156. {
  157. cmGrRC_t rc = kOkGrRC;
  158. _cmGrPgFinal(p);
  159. cmMemFree(p);
  160. return rc;
  161. }
  162. unsigned _cmGrPgGrHandleToVwIndex( cmGrPg_t* p, cmGrH_t grH )
  163. {
  164. unsigned i;
  165. for(i=0; i<p->vn; ++i)
  166. if( cmHandlesAreEqual(p->viewV[i].grH,grH) )
  167. return i;
  168. return cmInvalidIdx;
  169. }
  170. void _cmGrPageCallback( void* arg, cmGrH_t grH, cmGrCbId_t id, unsigned eventFlags, cmGrKeyCodeId_t keycode )
  171. {
  172. cmGrPg_t* p = (cmGrPg_t*)arg;
  173. switch(id)
  174. {
  175. case kCreateCbGrId:
  176. case kDestroyCbGrId:
  177. case kLocalPtCbGrId:
  178. case kGlobalPtCbGrId:
  179. case kPhysExtCbGrId:
  180. case kViewExtCbGrId:
  181. case kSelectExtCbGrId:
  182. if( p->cbFunc != NULL )
  183. p->cbFunc(p->cbArg,grH,id,eventFlags,keycode);
  184. break;
  185. case kKeyUpCbGrId:
  186. case kKeyDnCbGrId:
  187. {
  188. cmGrVwH_t vwH;
  189. cmGrPgH_t pgH;
  190. pgH.h = p;
  191. if(cmGrViewIsValid(vwH =cmGrPageFocusedView(pgH)))
  192. if( p->cbFunc != NULL )
  193. p->cbFunc(p->cbArg,cmGrViewGrHandle(vwH),id,eventFlags,keycode);
  194. }
  195. break;
  196. case kFocusCbGrId:
  197. {
  198. unsigned i;
  199. if((i = _cmGrPgGrHandleToVwIndex(p,grH)) != cmInvalidIdx )
  200. {
  201. cmGrPgH_t h;
  202. h.h = p;
  203. // if the focus is changing
  204. if( i != p->focusIdx )
  205. {
  206. // inform the prev view that it is losing focus
  207. if( p->focusIdx != cmInvalidIdx )
  208. cmGrPageViewFocus(h,p->focusIdx,false);
  209. // inform the new view that it is gaining focus
  210. cmGrPageViewFocus(h,i,true);
  211. if( p->cbFunc != NULL )
  212. p->cbFunc(p->cbArg,grH,id,eventFlags,keycode);
  213. }
  214. }
  215. }
  216. break;
  217. default:
  218. { assert(0); }
  219. }
  220. }
  221. cmGrRC_t cmGrPageCreate( cmCtx_t* ctx, cmGrPgH_t* hp, cmGrCbFunc_t cbFunc, void* cbArg )
  222. {
  223. cmGrRC_t rc;
  224. if((rc = cmGrPageDestroy(hp)) != kOkGrRC )
  225. return rc;
  226. cmGrPg_t* p = cmMemAllocZ(cmGrPg_t,1);
  227. cmErrSetup(&p->err,&ctx->rpt,"cmGrPage");
  228. p->cbFunc = cbFunc;
  229. p->cbArg = cbArg;
  230. p->ctx = *ctx;
  231. hp->h = p;
  232. if(rc != kOkGrRC )
  233. _cmGrPgDestroy(p);
  234. return rc;
  235. }
  236. cmGrRC_t cmGrPageDestroy( cmGrPgH_t* hp )
  237. {
  238. cmGrRC_t rc;
  239. if(hp==NULL || cmGrPageIsValid(*hp) == false )
  240. return kOkGrRC;
  241. cmGrPg_t* p = _cmGrPgHandleToPtr(*hp);
  242. if((rc = _cmGrPgDestroy(p)) != kOkGrRC )
  243. return rc;
  244. hp->h = NULL;
  245. return rc;
  246. }
  247. bool cmGrPageIsValid( cmGrPgH_t h )
  248. { return h.h != NULL; }
  249. cmGrRC_t cmGrPageClear( cmGrPgH_t h )
  250. {
  251. cmGrRC_t rc = kOkGrRC;
  252. unsigned i;
  253. for(i=0; i<cmGrPageViewCount(h); ++i)
  254. {
  255. cmGrVwH_t vwH = cmGrPageViewHandle(h,i);
  256. assert( cmGrViewIsValid(vwH) );
  257. if((rc = cmGrViewClear(vwH)) != kOkGrRC )
  258. break;
  259. }
  260. return rc;
  261. }
  262. // Calcuate the position of each view using the p->pext, and the row/col proportion vectors
  263. // This function calculates the outer page around each view.
  264. // It must be called whenever the size of the window holding the page changes.
  265. bool _cmGrPgLayoutVwPosition( cmGrPg_t* p )
  266. {
  267. enum { kVBord=4, kHBord=4 };
  268. // verify that the page state is sane
  269. if( p->rn==0 || p->cn==0 || p->pext.sz.h==0 || p->pext.sz.w==0)
  270. goto errLabel;
  271. else
  272. {
  273. unsigned i,j;
  274. int x=p->pext.loc.x;
  275. int y=p->pext.loc.y;
  276. // calculate the total page width/height w/o internal borders
  277. int h = p->pext.sz.h - ((p->rn - 1) * kVBord);
  278. int w = p->pext.sz.w - ((p->cn - 1) * kHBord);
  279. // verify that the page area exists
  280. if( h<=0 || w<=0 )
  281. goto errLabel;
  282. // force the row/col proportion vectors to sum to 1.0
  283. cmVOD_NormalizeProbability(p->rpropV,p->rn);
  284. cmVOD_NormalizeProbability(p->cpropV,p->cn);
  285. // determine the row height
  286. for(i=0; i<p->rn; ++i)
  287. {
  288. unsigned hh = (unsigned)floor(p->rpropV[i] * h);
  289. if( hh == 0 )
  290. goto errLabel;
  291. for(j=0; j<p->vn; ++j)
  292. if( p->viewV[j].ri == i )
  293. {
  294. p->viewV[j].pext.loc.y = y;
  295. p->viewV[j].pext.sz.h = hh;
  296. }
  297. y += hh + kVBord;
  298. }
  299. // determine the column width
  300. for(i=0; i<p->cn; ++i)
  301. {
  302. unsigned ww = (unsigned)floor(p->cpropV[i] * w);
  303. if( ww == 0 )
  304. goto errLabel;
  305. for(j=0; j<p->vn; ++j)
  306. if( p->viewV[j].ci == i )
  307. {
  308. p->viewV[j].pext.loc.x = x;
  309. p->viewV[j].pext.sz.w = ww;
  310. }
  311. x += ww + kHBord;
  312. }
  313. p->flags = cmClrFlag(p->flags,kNotValidFl);
  314. return true;
  315. }
  316. errLabel:
  317. p->flags = cmSetFlag(p->flags,kNotValidFl);
  318. return false;
  319. }
  320. // Calculate the layout for a given view.
  321. // txW = max hash label width on x-axis
  322. // txH = hash label height on x-axis
  323. void _cmGrPgLayoutView( cmGrPg_t* p, cmGrPgVw_t* vp, cmGrDcH_t dcH )
  324. {
  325. enum { kVBord=2, kHBord=2 };
  326. int x0 = vp->pext.loc.x + kHBord;
  327. int y0 = vp->pext.loc.y + kVBord;
  328. int w = vp->pext.sz.w - 2*kHBord;
  329. int h = vp->pext.sz.h - 2*kVBord;
  330. int y = y0;
  331. int x = x0;
  332. cmGrPSz_t sz;
  333. // Create a negative string with a repeating decimal to simulate an arbitrary hash label
  334. // Use the measurements from this string to compute the geometry of the view layouts.
  335. char label[ kHashCharCnt + 1];
  336. snprintf(label,kHashCharCnt,"%f",-4.0/3.0);
  337. label[kHashCharCnt] = 0;
  338. int mlx,mrx,mty,mby;
  339. int i;
  340. // add vertical space for the view title
  341. if( vp->title != NULL )
  342. {
  343. cmGrDcFontSetAndMeasure(dcH, vp->fontId, vp->fontSize, vp->fontStyle, vp->title, &sz );
  344. y += sz.h;
  345. vp->titlePt.y = y;
  346. vp->titlePt.x = vp->pext.loc.x + vp->pext.sz.w/2;
  347. y += 2;
  348. }
  349. cmGrPgAxis_t* ap = vp->axis + kTopGrIdx;
  350. // add vertical space for the top axis title
  351. if( ap->title != NULL )
  352. {
  353. cmGrDcFontSetAndMeasure(dcH, ap->titleFontId, ap->titleFontSize, ap->titleFontStyle, ap->title, &sz );
  354. y += sz.h;
  355. ap->titlePt.y = y;
  356. y += 4;
  357. }
  358. // add vertical space for top axis hash labels
  359. if( cmIsFlag(ap->flags,kHashLabelGrFl ) )
  360. {
  361. cmGrDcFontSetAndMeasure(dcH, ap->labelFontId, ap->labelFontSize, ap->labelFontStyle, label, &sz );
  362. y += sz.h;
  363. ap->labelPt.y = y;
  364. y += 1;
  365. }
  366. // calc vertical space for top axis hash marks
  367. if( cmIsFlag(ap->flags,kHashMarkGrFl ) )
  368. {
  369. mty = y;
  370. y += ap->hashLength + 1;
  371. }
  372. // set the internal pext vertical location
  373. vp->iext.loc.y = y;
  374. ap = vp->axis + kBottomGrIdx;
  375. y = y0 + h - 1 - kVBord;
  376. // subtract vertical space for bottom axis title
  377. if( ap->title != NULL )
  378. {
  379. cmGrDcFontSetAndMeasure(dcH, ap->titleFontId, ap->titleFontSize, ap->titleFontStyle, ap->title, &sz );
  380. ap->titlePt.y = y;
  381. y -= sz.h + 4;
  382. }
  383. // calc vertical space for bottom axis hash label
  384. if( cmIsFlag(ap->flags,kHashLabelGrFl) )
  385. {
  386. cmGrDcFontSetAndMeasure(dcH, ap->labelFontId, ap->labelFontSize, ap->labelFontStyle, label, &sz );
  387. ap->labelPt.y = y;
  388. y -= sz.h + 2;
  389. }
  390. // calc vertical space for bottom axis hash mark
  391. if( cmIsFlag(ap->flags,kHashMarkGrFl) )
  392. {
  393. mby = y;
  394. y -= ap->hashLength + 1;
  395. }
  396. // set the internal pext height
  397. vp->iext.sz.h = y - vp->iext.loc.y + 1;
  398. ap = vp->axis + kLeftGrIdx;
  399. // add horizontal space for the left axis title
  400. if( ap->title != NULL )
  401. {
  402. cmGrDcFontSetAndMeasure(dcH, ap->titleFontId, ap->titleFontSize, ap->titleFontStyle, ap->title, &sz );
  403. x += sz.h; // use txH as approx of char. width for rotated title
  404. ap->titlePt.x = x;
  405. x += 4;
  406. }
  407. // add horizontal space for left axis hash labels
  408. if( cmIsFlag(ap->flags,kHashLabelGrFl ) )
  409. {
  410. cmGrDcFontSetAndMeasure(dcH, ap->labelFontId, ap->labelFontSize, ap->labelFontStyle, label, &sz );
  411. ap->labelPt.x = x;
  412. x += sz.w + 3;
  413. }
  414. // calc horizontal space for left axis hash marks
  415. if( cmIsFlag(ap->flags,kHashMarkGrFl ) )
  416. {
  417. mlx = x;
  418. x += ap->hashLength + 1;
  419. }
  420. // set the internal pext horz location
  421. vp->iext.loc.x = x;
  422. ap = vp->axis + kRightGrIdx;
  423. x = x0 + w - 1 - kVBord;
  424. // subtract horizontal space for right axis title
  425. if( ap->title != NULL )
  426. {
  427. cmGrDcFontSetAndMeasure(dcH, ap->titleFontId, ap->titleFontSize, ap->titleFontStyle, ap->title, &sz );
  428. ap->titlePt.x = x;
  429. x -= sz.h + 2; // use txH as approx of char. width for rotated title
  430. }
  431. // calc horizontal space for right axis hash label
  432. if( cmIsFlag(ap->flags,kHashLabelGrFl) )
  433. {
  434. cmGrDcFontSetAndMeasure(dcH, ap->labelFontId, ap->labelFontSize, ap->labelFontStyle, label, &sz );
  435. x -= sz.w + 1;
  436. ap->labelPt.x = x;
  437. x -= 3;
  438. }
  439. // calc horizontal space for right axis hash mark
  440. if( cmIsFlag(ap->flags,kHashMarkGrFl) )
  441. {
  442. mrx = x;
  443. x -= ap->hashLength + 1;
  444. }
  445. // set the internal pext width
  446. vp->iext.sz.w = x - vp->iext.loc.x + 1;
  447. // calc the top hash count and alloc hash array
  448. ap = vp->axis + kTopGrIdx;
  449. cmGrDcFontSetAndMeasure(dcH, ap->labelFontId, ap->labelFontSize, ap->labelFontStyle, label, &sz );
  450. ap->hashCnt = cmMin(ap->maxHashCnt,(vp->iext.sz.w + sz.w) / sz.w);
  451. ap->hash = cmMemResizeZ( cmGrPgHash_t, ap->hash, vp->axis[ kTopGrIdx ].hashCnt );
  452. // calc the bottom hash count and alloc hash array
  453. ap = vp->axis + kBottomGrIdx;
  454. cmGrDcFontSetAndMeasure(dcH, ap->labelFontId, ap->labelFontSize, ap->labelFontStyle, label, &sz );
  455. ap->hashCnt = cmMin(ap->maxHashCnt,(vp->iext.sz.w + sz.w) / sz.w);
  456. ap->hash = cmMemResizeZ( cmGrPgHash_t, ap->hash, vp->axis[ kBottomGrIdx ].hashCnt );
  457. // calc the top hash mark line beg/end
  458. for(i=0; i< vp->axis[ kTopGrIdx ].hashCnt; ++i)
  459. {
  460. int x0 = round(vp->iext.loc.x - 1 + ((i * (vp->iext.sz.w + 1.0))/(vp->axis[ kTopGrIdx ].hashCnt-1)));
  461. vp->axis[kTopGrIdx].hash[i].xy0.y = mty;
  462. vp->axis[kTopGrIdx].hash[i].xy0.x = x0;
  463. vp->axis[kTopGrIdx].hash[i].xy1.y = vp->iext.loc.y - 1;
  464. vp->axis[kTopGrIdx].hash[i].xy1.x = x0;
  465. }
  466. // calc the bottom hash mark line beg/end
  467. for(i=0; i< vp->axis[ kBottomGrIdx ].hashCnt; ++i)
  468. {
  469. int x0 = round(vp->iext.loc.x - 1 + ((i * (vp->iext.sz.w + 1.0))/(vp->axis[ kBottomGrIdx ].hashCnt-1)));
  470. vp->axis[kBottomGrIdx].hash[i].xy0.y = mby;
  471. vp->axis[kBottomGrIdx].hash[i].xy0.x = x0;
  472. vp->axis[kBottomGrIdx].hash[i].xy1.y = cmGrPExtB(&vp->iext) + 1;
  473. vp->axis[kBottomGrIdx].hash[i].xy1.x = x0;
  474. }
  475. // calc the left hash count and alloc hash array
  476. ap = vp->axis + kLeftGrIdx;
  477. cmGrDcFontSetAndMeasure(dcH, ap->labelFontId, ap->labelFontSize, ap->labelFontStyle, label, &sz );
  478. ap->hashCnt = cmMin(ap->maxHashCnt,(vp->iext.sz.h + sz.h) / sz.h);
  479. ap->hash = cmMemResizeZ( cmGrPgHash_t, ap->hash, vp->axis[ kLeftGrIdx ].hashCnt );
  480. // calc right hash count and alloc hash array
  481. ap = vp->axis + kRightGrIdx;
  482. cmGrDcFontSetAndMeasure(dcH, ap->labelFontId, ap->labelFontSize, ap->labelFontStyle, label, &sz );
  483. ap->hashCnt = cmMin(ap->maxHashCnt,(vp->iext.sz.h + sz.h) / sz.h);
  484. ap->hash = cmMemResizeZ( cmGrPgHash_t, ap->hash, vp->axis[ kRightGrIdx ].hashCnt );
  485. // calc the left hash mark beg/end
  486. for(i=0; i< vp->axis[ kLeftGrIdx ].hashCnt; ++i)
  487. {
  488. int y0 = round(vp->iext.loc.y - 1 + ((i * (vp->iext.sz.h + 1.0))/(vp->axis[ kLeftGrIdx ].hashCnt-1)));
  489. vp->axis[kLeftGrIdx].hash[i].xy0.x = mlx;
  490. vp->axis[kLeftGrIdx].hash[i].xy0.y = y0;
  491. vp->axis[kLeftGrIdx].hash[i].xy1.x = vp->iext.loc.x - 1;
  492. vp->axis[kLeftGrIdx].hash[i].xy1.y = y0;
  493. }
  494. // calc the right hash mark beg/end
  495. for(i=0; i< vp->axis[ kRightGrIdx ].hashCnt; ++i)
  496. {
  497. int y0 = round(vp->iext.loc.y - 1 + ((i * (vp->iext.sz.h + 1.0))/(vp->axis[ kRightGrIdx ].hashCnt-1)));
  498. vp->axis[kRightGrIdx].hash[i].xy0.x = mrx;
  499. vp->axis[kRightGrIdx].hash[i].xy0.y = y0;
  500. vp->axis[kRightGrIdx].hash[i].xy1.x = cmGrPExtR(&vp->iext) + 1;
  501. vp->axis[kRightGrIdx].hash[i].xy1.y = y0;
  502. }
  503. // change the location of the view to match vp->iext
  504. if( cmGrIsValid( vp->grH ) )
  505. cmGrSetPhysExtentsE( vp->grH, &vp->iext );
  506. }
  507. bool _cmGrPageLayout( cmGrPg_t* p, cmGrDcH_t dcH )
  508. {
  509. unsigned i;
  510. if( cmIsNotFlag(p->flags,kDirtyFl) )
  511. return false;
  512. cmGrDcSetFontFamily(dcH,kHelveticaFfGrId);
  513. cmGrDcSetFontSize(dcH,10);
  514. // Create a negative string with a repeating decimal to simulate an arbitrary hash label
  515. // Use the measurements pgom this string to compute the geometry of the view layouts.
  516. /*
  517. char label[ kHashCharCnt + 1];
  518. cmGrPSz_t sz;
  519. snprintf(label,kHashCharCnt,"%f",-4.0/3.0);
  520. label[kHashCharCnt] = 0;
  521. cmGrDcMeasure(dcH,label,&sz);
  522. */
  523. _cmGrPgLayoutVwPosition(p);
  524. for(i=0; i<p->vn; ++i)
  525. {
  526. cmGrPgVw_t* vp = p->viewV + i;
  527. _cmGrPgLayoutView(p, vp, dcH );
  528. }
  529. p->flags = cmClrFlag(p->flags,kDirtyFl);
  530. return true;
  531. }
  532. cmGrRC_t cmGrPageInit( cmGrPgH_t h, const cmGrPExt_t* r, unsigned rn, unsigned cn, cmGrDcH_t dcH )
  533. {
  534. cmGrRC_t rc = kOkGrRC;
  535. cmGrPg_t* p = _cmGrPgHandleToPtr(h);
  536. unsigned i;
  537. _cmGrPgFinal(p);
  538. if( rn*cn > 0 )
  539. {
  540. p->pext = *r;
  541. p->rn = rn;
  542. p->cn = cn;
  543. p->vn = rn*cn;
  544. p->rpropV = cmMemAllocZ(double, rn);
  545. p->cpropV = cmMemAllocZ(double, cn);
  546. p->viewV = cmMemAllocZ(cmGrPgVw_t, p->vn);
  547. p->flags = kDirtyFl;
  548. p->focusIdx = cmInvalidIdx;
  549. p->fontId = kHelveticaFfGrId;
  550. p->fontStyle = kNormalFsGrFl;
  551. p->fontSize = 16;
  552. // setup the view defaults
  553. for(i=0; i<p->vn; ++i)
  554. {
  555. cmGrPgVw_t* vp = p->viewV + i;
  556. vp->p = p;
  557. vp->ri = i % p->rn;
  558. vp->ci = i / p->rn;
  559. vp->fontId = kHelveticaFfGrId;
  560. vp->fontStyle = kNormalFsGrFl;
  561. vp->fontSize = 14;
  562. unsigned j;
  563. for(j=0; j<kAxisGrCnt; ++j)
  564. {
  565. cmGrPgAxis_t* ap = vp->axis + j;
  566. ap->vp = p->viewV + i;
  567. ap->maxHashCnt = kMaxHashCnt;
  568. ap->hashLength = kHashLength;
  569. ap->flags = kHashMarkGrFl | kHashLabelGrFl;
  570. ap->titleFontId = kHelveticaFfGrId;
  571. ap->titleFontStyle = kNormalFsGrFl;
  572. ap->titleFontSize = 10;
  573. ap->labelFontId = kHelveticaFfGrId;
  574. ap->labelFontStyle = kNormalFsGrFl;
  575. ap->labelFontSize = 10;
  576. }
  577. }
  578. // setup the default row proportions
  579. for(i=0; i<p->rn; ++i)
  580. p->rpropV[i] = 1.0/p->rn;
  581. // setup the default col proportions
  582. for(i=0; i<p->cn; ++i)
  583. p->cpropV[i] = 1.0/p->cn;
  584. // _cmGrPgLayoutVw() needs to be called.
  585. p->flags = cmSetFlag(p->flags,kDirtyFl);
  586. // layout the page
  587. // kpl _cmGrPageLayout(p, dcH );
  588. // notify the application that views have been created
  589. for(i=0; i<rn*cn; ++i)
  590. {
  591. cmGrPgVw_t* vp = p->viewV + i;
  592. // Set the 'id' assoc'd with this views cmGrH_t handle to 'i'.
  593. // This will allow the grH to return the index of the plot.
  594. if((rc = cmGrCreate(&p->ctx,&vp->grH,i,kExpandViewGrFl,_cmGrPageCallback,p,NULL)) != kOkGrRC )
  595. break;
  596. }
  597. }
  598. return rc;
  599. }
  600. cmGrRC_t cmGrPageResize( cmGrPgH_t h, const cmGrPExt_t* r, cmGrDcH_t dcH )
  601. {
  602. cmGrPg_t* p = _cmGrPgHandleToPtr(h);
  603. p->pext = *r;
  604. // _cmGrPgLayoutVw() needs to be called.
  605. p->flags = cmSetFlag(p->flags,kDirtyFl);
  606. // layout the page
  607. // kpl _cmGrPageLayout(p, dcH );
  608. return kOkGrRC;
  609. }
  610. void cmGrPageRect( cmGrPgH_t h, cmGrPExt_t* r )
  611. {
  612. cmGrPg_t* p = _cmGrPgHandleToPtr(h);
  613. *r = p->pext;
  614. }
  615. unsigned cmGrPageViewCount( cmGrPgH_t h )
  616. {
  617. cmGrPg_t* p = _cmGrPgHandleToPtr(h);
  618. return p->vn;
  619. }
  620. void _cmGrViewSetTitle(cmGrPgVw_t* vp, const cmChar_t* title )
  621. {
  622. if( title == vp->title || (title != NULL && vp->title!=NULL && strcmp(title,vp->title)==0 ))
  623. return;
  624. cmMemPtrFree(&vp->title);
  625. if( title != NULL )
  626. {
  627. assert( vp->title == NULL );
  628. vp->title = cmMemAllocStr(title);
  629. }
  630. vp->p->flags = cmSetFlag(vp->p->flags, kDirtyFl);
  631. }
  632. void _cmGrAxisSetTitle( cmGrPgAxis_t* ap, const cmChar_t* title )
  633. {
  634. if( title == ap->title || (title != NULL && ap->title!=NULL && strcmp(title,ap->title)==0 ))
  635. return;
  636. cmMemPtrFree(&ap->title);
  637. if( title != NULL )
  638. {
  639. assert( ap->title == NULL );
  640. ap->title = cmMemAllocStr(title);
  641. }
  642. ap->vp->p->flags = cmSetFlag(ap->vp->p->flags, kDirtyFl);
  643. }
  644. void _cmGrPgDrawHashMarks( cmGrPg_t* p, cmGrPgVw_t* vp, cmGrDcH_t dcH, unsigned lineColor )
  645. {
  646. int i,j;
  647. cmGrDcSetColor(dcH, lineColor );
  648. cmGrDcSetPenWidth( dcH, 1 );
  649. for(j=0; j<kAxisGrCnt; ++j )
  650. {
  651. cmGrPgAxis_t* ap = vp->axis + j;
  652. if( cmIsFlag(ap->flags, kHashMarkGrFl) )
  653. for(i=0; i<ap->hashCnt; ++i)
  654. {
  655. cmGrPgHash_t* hp = ap->hash + i;
  656. cmGrDcDrawLine(dcH, hp->xy0.x, hp->xy0.y, hp->xy1.x, hp->xy1.y);
  657. }
  658. }
  659. // draw border 1 pixel outside of iext
  660. cmGrDcDrawRect(dcH,vp->iext.loc.x-1,vp->iext.loc.y-1,vp->iext.sz.w+2,vp->iext.sz.h+2);
  661. //printf("pgm: x:%i y:%i\n", vp->iext.loc.x, vp->iext.loc.y);
  662. // draw the view border
  663. //cmGrDcDrawRect(dcH,vp->pext.loc.x,vp->pext.loc.y,vp->pext.sz.w,vp->pext.sz.h);
  664. }
  665. void _cmGrPgHashValueToLabel( cmGrPgAxis_t* ap, cmChar_t* label, unsigned labelCharCnt, cmGrV_t value )
  666. {
  667. if( ap->func == NULL )
  668. snprintf(label,labelCharCnt,"%f",value);
  669. else
  670. {
  671. ap->func->func( ap->func->arg, label, labelCharCnt, value );
  672. }
  673. }
  674. void _cmGrPgDrawHashLabels( cmGrPg_t* p, cmGrPgVw_t* vp, cmGrDcH_t dcH, unsigned textColor )
  675. {
  676. int i;
  677. cmGrVExt_t vext;
  678. char s[ kHashCharCnt+1 ];
  679. s[kHashCharCnt]=0;
  680. cmGrViewExtents( vp->grH, &vext );
  681. //cmGrVExtPrint("hash:",&vext);
  682. cmGrDcSetColor(dcH, textColor );
  683. cmGrPgAxis_t* ap = vp->axis + kLeftGrIdx;
  684. cmGrDcSetFont( dcH, ap->labelFontId, ap->labelFontSize, ap->labelFontStyle );
  685. // draw the left axis hash labels
  686. if( cmIsFlag(ap->flags, kHashLabelGrFl ) )
  687. {
  688. for(i=0; i<vp->axis[ kLeftGrIdx ].hashCnt; ++i)
  689. {
  690. cmGrPSz_t sz;
  691. double v = vext.loc.y + vext.sz.h - (i * vext.sz.h / (ap->hashCnt-1) );
  692. _cmGrPgHashValueToLabel(ap,s,kHashCharCnt,v);
  693. cmGrDcMeasure(dcH,s,&sz);
  694. int y = ap->hash[i].xy0.y;
  695. cmGrDcDrawText(dcH, s, ap->labelPt.x, y + (sz.h/2) );
  696. }
  697. }
  698. ap = vp->axis + kRightGrIdx;
  699. cmGrDcSetFont( dcH, ap->labelFontId, ap->labelFontSize, ap->labelFontStyle );
  700. // draw the right axis hash labels
  701. if( cmIsFlag(ap->flags, kHashLabelGrFl ))
  702. {
  703. for(i=0; i<ap->hashCnt; ++i)
  704. {
  705. cmGrPSz_t sz;
  706. double v = vext.loc.y + vext.sz.h - (i * vext.sz.h / (ap->hashCnt-1) );
  707. _cmGrPgHashValueToLabel(ap,s,kHashCharCnt,v);
  708. cmGrDcMeasure(dcH,s,&sz);
  709. int y = ap->hash[i].xy0.y;
  710. cmGrDcDrawText(dcH, s, ap->labelPt.x, y + (sz.h/2));
  711. }
  712. }
  713. // draw the top axis hash labels
  714. ap = vp->axis + kTopGrIdx;
  715. cmGrDcSetFont( dcH, ap->labelFontId, ap->labelFontSize, ap->labelFontStyle );
  716. if( cmIsFlag(ap->flags, kHashLabelGrFl ) )
  717. {
  718. for(i=0; i<ap->hashCnt; ++i)
  719. {
  720. cmGrPSz_t sz;
  721. double v = vext.loc.x + (i * vext.sz.w / (ap->hashCnt-1));
  722. _cmGrPgHashValueToLabel(ap,s,kHashCharCnt,v);
  723. cmGrDcMeasure(dcH,s,&sz);
  724. cmGrDcDrawText(dcH, s, ap->hash[i].xy0.x - sz.w/2, ap->labelPt.y );
  725. }
  726. }
  727. // draw the bottom axis hash labels
  728. ap = vp->axis + kBottomGrIdx;
  729. cmGrDcSetFont( dcH, ap->labelFontId, ap->labelFontSize, ap->labelFontStyle );
  730. if( cmIsFlag(ap->flags, kHashLabelGrFl ) )
  731. {
  732. for(i=0; i<ap->hashCnt; ++i)
  733. {
  734. cmGrPSz_t sz;
  735. double v = vext.loc.x + (i * vext.sz.w / (ap->hashCnt-1));
  736. _cmGrPgHashValueToLabel(ap,s,kHashCharCnt,v);
  737. cmGrDcMeasure(dcH,s,&sz);
  738. cmGrDcDrawText(dcH, s, ap->hash[i].xy0.x - sz.w/2, ap->labelPt.y );
  739. }
  740. }
  741. }
  742. void _cmGrPgDrawAxisTitles( cmGrPg_t* p, cmGrPgVw_t* vp, cmGrDcH_t dcH )
  743. {
  744. unsigned i;
  745. for(i=0; i<kAxisGrCnt; ++i)
  746. {
  747. cmGrPgAxis_t* ap = vp->axis + i;
  748. if( ap->title != NULL )
  749. {
  750. cmGrPSz_t sz;
  751. cmGrDcFontSetAndMeasure( dcH, ap->titleFontId, ap->titleFontSize, ap->titleFontStyle, ap->title, &sz );
  752. if( i==kBottomGrIdx || i==kTopGrIdx )
  753. {
  754. int x = vp->iext.loc.x + (vp->iext.sz.w/2) - (sz.w/2);
  755. cmGrDcDrawText( dcH, ap->title, x, ap->titlePt.y );
  756. }
  757. if( i==kLeftGrIdx || i==kRightGrIdx )
  758. {
  759. int y = vp->iext.loc.y + (vp->iext.sz.h/2) + (sz.w/2);
  760. cmGrDcDrawTextRot( dcH, ap->title, ap->titlePt.x, y, 90 );
  761. }
  762. }
  763. }
  764. }
  765. void cmGrPageViewFocus( cmGrPgH_t h, unsigned vwIdx, bool enableFl )
  766. {
  767. cmGrPg_t* p = _cmGrPgHandleToPtr(h);
  768. assert( vwIdx < p->vn );
  769. if( enableFl )
  770. p->focusIdx = vwIdx;
  771. else
  772. {
  773. if( p->focusIdx == vwIdx )
  774. p->focusIdx = cmInvalidId;
  775. }
  776. }
  777. cmGrVwH_t cmGrPageFocusedView( cmGrPgH_t h )
  778. {
  779. cmGrPg_t* p = _cmGrPgHandleToPtr(h);
  780. cmGrVwH_t vwH = cmGrVwNullHandle;
  781. if( p->focusIdx != cmInvalidIdx )
  782. vwH.h = p->viewV + p->focusIdx;
  783. return vwH;
  784. }
  785. bool cmGrPageLayout( cmGrPgH_t h, cmGrDcH_t dcH )
  786. {
  787. cmGrPg_t* p = _cmGrPgHandleToPtr(h);
  788. cmGrDcPushCtx(dcH);
  789. bool fl = _cmGrPageLayout(p,dcH);
  790. cmGrDcPopCtx(dcH);
  791. return fl;
  792. }
  793. void cmGrPageDraw( cmGrPgH_t h, cmGrDcH_t dcH )
  794. {
  795. unsigned i;
  796. cmGrPg_t* p = _cmGrPgHandleToPtr(h);
  797. cmGrDcPushCtx(dcH);
  798. _cmGrPageLayout(p,dcH);
  799. cmGrDcSetColor(dcH,kBlackGrId);
  800. // for each view
  801. for(i=0; i<p->vn; ++i)
  802. {
  803. cmGrPgVw_t* vp = p->viewV + i;
  804. unsigned lineColor = p->focusIdx==i ? kRedGrId : kBlackGrId;
  805. _cmGrPgDrawHashMarks( p, vp, dcH, lineColor );
  806. _cmGrPgDrawHashLabels( p, vp, dcH, kBlackGrId);
  807. _cmGrPgDrawAxisTitles( p, vp, dcH );
  808. if( vp->title != NULL )
  809. {
  810. cmGrPSz_t sz;
  811. cmGrDcFontSetAndMeasure(dcH,vp->fontId,vp->fontSize,vp->fontStyle,vp->title,&sz);
  812. cmGrDcDrawText(dcH,vp->title, vp->titlePt.x - sz.w/2, vp->titlePt.y );
  813. }
  814. }
  815. cmGrDcPopCtx(dcH);
  816. }
  817. cmGrPgLabelFunc_t* _cmGrPageLabelIndexToRecd( cmGrPg_t* p, unsigned idx )
  818. {
  819. cmGrPgLabelFunc_t* lfp = p->funcs;
  820. unsigned i;
  821. for(i=0; i<idx && lfp!=NULL; ++i)
  822. lfp=lfp->link;
  823. return lfp;
  824. }
  825. cmGrPgLabelFunc_t* _cmGrPageLabelIdToRecd( cmGrPg_t* p, unsigned id )
  826. {
  827. cmGrPgLabelFunc_t* lfp = p->funcs;
  828. for(; lfp!=NULL; lfp=lfp->link)
  829. if( lfp->id == id )
  830. return lfp;
  831. return lfp;
  832. }
  833. unsigned cmGrPageLabelFuncRegister( cmGrPgH_t h, cmGrLabelFunc_t func, void* arg, const cmChar_t* label )
  834. {
  835. cmGrPg_t* p = _cmGrPgHandleToPtr(h);
  836. cmGrPgLabelFunc_t* lfp = cmMemAllocZ(cmGrPgLabelFunc_t,1);
  837. lfp->id = p->labelFuncId++;
  838. lfp->func = func;
  839. lfp->arg = arg;
  840. lfp->label = cmMemAllocStr(label);
  841. lfp->link = p->funcs;
  842. p->funcs = lfp;
  843. return lfp->id;
  844. }
  845. unsigned cmGrPageLabelFuncCount( cmGrPgH_t h )
  846. {
  847. cmGrPg_t* p = _cmGrPgHandleToPtr(h);
  848. cmGrPgLabelFunc_t* lfp = p->funcs;
  849. unsigned n = 0;
  850. for(; lfp != NULL; lfp=lfp->link )
  851. ++n;
  852. return n;
  853. }
  854. unsigned cmGrPageLabelFuncIndexToId( cmGrPgH_t h, unsigned index )
  855. {
  856. cmGrPgLabelFunc_t* lfp;
  857. cmGrPg_t* p = _cmGrPgHandleToPtr(h);
  858. if((lfp = _cmGrPageLabelIndexToRecd(p,index)) == NULL )
  859. return cmInvalidId;
  860. return lfp->id;
  861. }
  862. unsigned cmGrPageLabelFuncLabelToId( cmGrPgH_t h, const cmChar_t* label )
  863. {
  864. cmGrPg_t* p = _cmGrPgHandleToPtr(h);
  865. cmGrPgLabelFunc_t* lfp = p->funcs;
  866. unsigned i;
  867. for(i=0; lfp!=NULL; lfp=lfp->link,++i)
  868. if( lfp->label!=NULL && strcmp(label,lfp->label)==0 )
  869. return lfp->id;
  870. return cmInvalidId;
  871. }
  872. cmGrLabelFunc_t cmGrPageLabelFunc( cmGrPgH_t h, unsigned id )
  873. {
  874. cmGrPg_t* p = _cmGrPgHandleToPtr(h);
  875. cmGrPgLabelFunc_t* lfp = _cmGrPageLabelIdToRecd(p,id);
  876. assert( lfp != NULL );
  877. return lfp->func;
  878. }
  879. const cmChar_t* cmGrPageLabelFuncLabel( cmGrPgH_t h, unsigned id )
  880. {
  881. cmGrPg_t* p = _cmGrPgHandleToPtr(h);
  882. cmGrPgLabelFunc_t* lfp = _cmGrPageLabelIdToRecd(p,id);
  883. assert( lfp != NULL );
  884. return lfp->label;
  885. }
  886. void* cmGrPageLabelFuncArg( cmGrPgH_t h, unsigned id )
  887. {
  888. cmGrPg_t* p = _cmGrPgHandleToPtr(h);
  889. cmGrPgLabelFunc_t* lfp = _cmGrPageLabelIdToRecd(p,id);
  890. assert( lfp != NULL );
  891. return lfp->arg;
  892. }
  893. cmGrVwH_t cmGrPageViewHandle( cmGrPgH_t h, unsigned vwIdx )
  894. {
  895. cmGrPg_t* p = _cmGrPgHandleToPtr(h);
  896. cmGrVwH_t vwH;
  897. assert( vwIdx < p->vn );
  898. vwH.h = p->viewV + vwIdx;
  899. return vwH;
  900. }
  901. cmGrVwH_t cmGrPageGrHandleToView( cmGrPgH_t pgH, cmGrH_t grH )
  902. {
  903. cmGrPg_t* p = _cmGrPgHandleToPtr(pgH);
  904. cmGrVwH_t vwH = cmGrVwNullHandle;
  905. int i;
  906. for(i=0; i<p->vn; ++i)
  907. if( cmHandlesAreEqual(grH,p->viewV[i].grH) )
  908. {
  909. vwH.h = p->viewV + i;
  910. break;
  911. }
  912. return vwH;
  913. }
  914. bool cmGrViewIsValid( cmGrVwH_t h )
  915. { return h.h != NULL; }
  916. cmGrRC_t cmGrViewInit( cmGrVwH_t h, cmGrH_t grH, const cmChar_t* vwTitle, const cmChar_t* xLabel, const cmChar_t* yLabel )
  917. {
  918. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  919. vp->grH = grH;
  920. _cmGrViewSetTitle( vp, vwTitle );
  921. _cmGrAxisSetTitle( vp->axis + kBottomGrIdx, xLabel );
  922. _cmGrAxisSetTitle( vp->axis + kLeftGrIdx, yLabel );
  923. vp->p->flags = cmSetFlag(vp->p->flags, kDirtyFl);
  924. return kOkGrRC;
  925. }
  926. cmGrRC_t cmGrViewClear( cmGrVwH_t h )
  927. {
  928. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  929. cmGrH_t grH = cmGrViewGrHandle(h);
  930. assert( cmGrIsValid(grH) );
  931. cmGrRC_t rc = cmGrClear( grH );
  932. vp->p->flags = cmSetFlag(vp->p->flags, kDirtyFl);
  933. return rc;
  934. }
  935. cmGrRC_t cmGrViewPExt( cmGrVwH_t h, cmGrPExt_t* pext )
  936. {
  937. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  938. *pext = vp->iext;
  939. return kOkGrRC;
  940. }
  941. bool cmGrViewHasFocus( cmGrVwH_t h )
  942. {
  943. if( cmGrViewIsValid(h) == false )
  944. return false;
  945. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  946. if( vp->p->focusIdx == cmInvalidIdx )
  947. return false;
  948. return cmGrId(vp->grH) == vp->p->focusIdx;
  949. }
  950. cmGrH_t cmGrViewGrHandle( cmGrVwH_t h )
  951. {
  952. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  953. return vp->grH;
  954. }
  955. void cmGrViewSetCfg( cmGrVwH_t h, unsigned cfgFlags )
  956. {
  957. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  958. cmGrSetCfgFlags( vp->grH, cfgFlags );
  959. vp->p->flags = cmSetFlag(vp->p->flags, kDirtyFl);
  960. }
  961. unsigned cmGrViewCfg( cmGrVwH_t h )
  962. {
  963. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  964. return cmGrCfgFlags( vp->grH );
  965. }
  966. void cmGrViewSetTitle( cmGrVwH_t h, const cmChar_t* title )
  967. {
  968. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  969. _cmGrViewSetTitle( vp, title );
  970. }
  971. const cmChar_t* cmGrViewTitle( cmGrVwH_t h )
  972. {
  973. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  974. return vp->title;
  975. }
  976. void cmGrViewSetFontFamily( cmGrVwH_t h, unsigned id )
  977. {
  978. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  979. if( vp->fontId != id )
  980. {
  981. vp->fontId = id;
  982. vp->p->flags = cmSetFlag(vp->p->flags, kDirtyFl);
  983. }
  984. }
  985. unsigned cmGrViewFontFamily( cmGrVwH_t h )
  986. {
  987. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  988. return vp->fontId;
  989. }
  990. void cmGrViewSetFontStyle( cmGrVwH_t h, unsigned flags )
  991. {
  992. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  993. if( vp->fontStyle != flags )
  994. {
  995. vp->fontStyle = flags;
  996. vp->p->flags = cmSetFlag(vp->p->flags, kDirtyFl);
  997. }
  998. }
  999. unsigned cmGrViewFontStyle( cmGrVwH_t h )
  1000. {
  1001. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  1002. return vp->fontStyle;
  1003. }
  1004. void cmGrViewSetFontSize( cmGrVwH_t h, unsigned size )
  1005. {
  1006. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  1007. if( vp->fontSize != size )
  1008. {
  1009. vp->fontSize = size;
  1010. vp->p->flags = cmSetFlag(vp->p->flags, kDirtyFl);
  1011. }
  1012. }
  1013. unsigned cmGrViewFontSize( cmGrVwH_t h )
  1014. {
  1015. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  1016. return vp->fontSize;
  1017. }
  1018. void cmGrViewSetLabelFunc( cmGrVwH_t h, cmGrAxisIdx_t axisId, unsigned pgLabelFuncId )
  1019. {
  1020. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  1021. cmGrPgLabelFunc_t** lfpp = NULL;
  1022. switch( axisId )
  1023. {
  1024. case kLeftGrIdx:
  1025. case kRightGrIdx:
  1026. lfpp = &vp->yfunc;
  1027. break;
  1028. case kTopGrIdx:
  1029. case kBottomGrIdx:
  1030. lfpp = &vp->xfunc;
  1031. break;
  1032. default:
  1033. { assert(0); }
  1034. }
  1035. assert( lfpp != NULL );
  1036. *lfpp = _cmGrPageLabelIdToRecd(vp->p, pgLabelFuncId );
  1037. }
  1038. const cmChar_t* cmGrViewValue( cmGrVwH_t h, cmGrViewValueId_t id, cmChar_t* buf, unsigned bufCharCnt )
  1039. {
  1040. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  1041. cmGrPgLabelFunc_t* lfp = NULL;
  1042. cmGrH_t grH = vp->grH;
  1043. cmGrV_t v;
  1044. cmGrVPt_t pt0,pt1;
  1045. switch( id )
  1046. {
  1047. case kLocalX_VwId:
  1048. v = cmGrLocalPt(grH)->x;
  1049. lfp = vp->xfunc;
  1050. break;
  1051. case kLocalY_VwId:
  1052. v = cmGrLocalPt(grH)->y;
  1053. lfp = vp->yfunc;
  1054. break;
  1055. case kGlobalX_VwId:
  1056. v = cmGrGlobalPt(grH)->x;
  1057. lfp = vp->xfunc;
  1058. break;
  1059. case kGlobalY_VwId:
  1060. v = cmGrGlobalPt(grH)->y;
  1061. lfp = vp->yfunc;
  1062. break;
  1063. case kSelX0_VwId:
  1064. cmGrSelectPoints(grH,&pt0,NULL);
  1065. v = pt0.x;
  1066. lfp = vp->xfunc;
  1067. break;
  1068. case kSelY0_VwId:
  1069. cmGrSelectPoints(grH,&pt0,NULL);
  1070. v = pt0.y;
  1071. lfp = vp->yfunc;
  1072. break;
  1073. case kSelX1_VwId:
  1074. cmGrSelectPoints(grH,NULL,&pt1);
  1075. v = pt1.x;
  1076. lfp = vp->xfunc;
  1077. break;
  1078. case kSelY1_VwId:
  1079. cmGrSelectPoints(grH,NULL,&pt1);
  1080. v = pt1.y;
  1081. lfp = vp->yfunc;
  1082. break;
  1083. case kSelW_VwId:
  1084. cmGrSelectPoints(grH,&pt0,&pt1);
  1085. v = fabs(pt1.x - pt0.x);
  1086. lfp = vp->xfunc;
  1087. break;
  1088. case kSelH_VwId:
  1089. cmGrSelectPoints(grH,&pt0,&pt1);
  1090. v = fabs(pt1.y - pt0.y);
  1091. lfp = vp->yfunc;
  1092. break;
  1093. default:
  1094. { assert(0); }
  1095. }
  1096. if( bufCharCnt > 0 )
  1097. {
  1098. buf[0]=0;
  1099. if( lfp != NULL )
  1100. lfp->func( lfp->arg, buf, bufCharCnt, v );
  1101. else
  1102. snprintf(buf,bufCharCnt,"%f",v);
  1103. }
  1104. return buf;
  1105. }
  1106. cmGrAxH_t cmGrViewAxisHandle( cmGrVwH_t h, cmGrAxisIdx_t axisIdx )
  1107. {
  1108. cmGrPgVw_t* vp = _cmGrPgVwHandleToPtr(h);
  1109. cmGrAxH_t axH;
  1110. assert( axisIdx < kAxisGrCnt );
  1111. axH.h = vp->axis + axisIdx;
  1112. return axH;
  1113. }
  1114. bool cmGrAxisIsValid( cmGrAxH_t h )
  1115. { return h.h != NULL; }
  1116. void cmGrAxisSetCfg( cmGrAxH_t h, unsigned flags )
  1117. {
  1118. cmGrPgAxis_t* ap = _cmGrPgAxisHandleToPtr(h);
  1119. if( ap->flags != flags )
  1120. {
  1121. ap->flags = flags;
  1122. ap->vp->p->flags = cmSetFlag(ap->vp->p->flags, kDirtyFl);
  1123. }
  1124. }
  1125. unsigned cmGrAxisCfg( cmGrAxH_t h )
  1126. {
  1127. cmGrPgAxis_t* ap = _cmGrPgAxisHandleToPtr(h);
  1128. return ap->flags;
  1129. }
  1130. void cmGrAxisSetTitle( cmGrAxH_t h, const cmChar_t* title )
  1131. {
  1132. cmGrPgAxis_t* ap = _cmGrPgAxisHandleToPtr(h);
  1133. _cmGrAxisSetTitle(ap,title);
  1134. }
  1135. const cmChar_t* cmGrAxisTitle( cmGrAxH_t h )
  1136. {
  1137. cmGrPgAxis_t* ap = _cmGrPgAxisHandleToPtr(h);
  1138. return ap->title;
  1139. }
  1140. void cmGrAxisSetTitleFontFamily( cmGrAxH_t h, unsigned id )
  1141. {
  1142. cmGrPgAxis_t* ap = _cmGrPgAxisHandleToPtr(h);
  1143. if( ap->titleFontId != id )
  1144. {
  1145. ap->titleFontId = id;
  1146. ap->vp->p->flags = cmSetFlag(ap->vp->p->flags, kDirtyFl);
  1147. }
  1148. }
  1149. unsigned cmGrAxisTitleFontFamily( cmGrAxH_t h )
  1150. {
  1151. cmGrPgAxis_t* ap = _cmGrPgAxisHandleToPtr(h);
  1152. return ap->titleFontId;
  1153. }
  1154. void cmGrAxisTitleSetFontStyle( cmGrAxH_t h, unsigned flags )
  1155. {
  1156. cmGrPgAxis_t* ap = _cmGrPgAxisHandleToPtr(h);
  1157. if( ap->titleFontStyle != flags )
  1158. {
  1159. ap->titleFontStyle = flags;
  1160. ap->vp->p->flags = cmSetFlag(ap->vp->p->flags, kDirtyFl);
  1161. }
  1162. }
  1163. unsigned cmGrAxisTitleFontStyle( cmGrAxH_t h )
  1164. {
  1165. cmGrPgAxis_t* ap = _cmGrPgAxisHandleToPtr(h);
  1166. return ap->titleFontStyle;
  1167. }
  1168. void cmGrAxisTitleSetFontSize( cmGrAxH_t h, unsigned size )
  1169. {
  1170. cmGrPgAxis_t* ap = _cmGrPgAxisHandleToPtr(h);
  1171. if( ap->titleFontSize != size )
  1172. {
  1173. ap->titleFontSize = size;
  1174. ap->vp->p->flags = cmSetFlag(ap->vp->p->flags, kDirtyFl);
  1175. }
  1176. }
  1177. unsigned cmGrAxisTitleFontSize( cmGrAxH_t h )
  1178. {
  1179. cmGrPgAxis_t* ap = _cmGrPgAxisHandleToPtr(h);
  1180. return ap->titleFontSize;
  1181. }
  1182. void cmGrAxisSetLabelFunc( cmGrAxH_t h, unsigned id )
  1183. {
  1184. cmGrPgAxis_t* ap = _cmGrPgAxisHandleToPtr(h);
  1185. ap->func = _cmGrPageLabelIdToRecd( ap->vp->p, id );
  1186. }