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

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