x3carbon.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  1. #include "x3.h"
  2. #include "x3common.h"
  3. /* Globals for managing sync */
  4. #define VERBOSE
  5. #define kX3ViewClassID CFSTR("com.levien.x3.X3View")
  6. #define kX3ViewPrivate 'X3_v'
  7. /* Some utility-type functions. */
  8. UInt32 x3mkmultichar(const char *s)
  9. {
  10. int len = strlen(s);
  11. int i;
  12. UInt32 result = 0;
  13. for (i = 0; i < (len > 4 ? 4 : len); i++)
  14. result = (result << 8) + (unsigned char)s[i];
  15. for (; i < 4; i++)
  16. result = (result << 8) + ' ';
  17. return result;
  18. }
  19. char *x3multicharstr(UInt32 mc, char buf[5])
  20. {
  21. int i, len;
  22. for (i = 0; i < 4; i++)
  23. if (((mc >> (8 * i)) & 0xff) != ' ') break;
  24. len = 4 - i;
  25. for (i = 0; i < len; i++)
  26. buf[i] = (mc >> (24 - 8 * i)) & 0xff;
  27. buf[len] = 0;
  28. return buf;
  29. }
  30. void x3widget_init(x3widget *w, const x3type *type)
  31. {
  32. w->type = type;
  33. w->name = NULL;
  34. w->parent = NULL;
  35. w->var = x3carbonnone;
  36. w->u.window = NULL;
  37. w->n_children = 0;
  38. w->children = NULL;
  39. }
  40. static x3widget *x3widget_new_container(x3widget *parent, char *name,
  41. const x3type *type)
  42. {
  43. x3widget *result = (x3widget *)malloc(sizeof(x3widget));
  44. x3widget_init(result, type);
  45. result->name = name ? strdup(name) : NULL;
  46. x3add(parent, result);
  47. x3qsizereq(result);
  48. return result;
  49. }
  50. static x3widget *x3widget_new_hiview(x3widget *parent, char *name,
  51. const x3type *type,
  52. HIViewRef hiview)
  53. {
  54. x3widget *result = (x3widget *)malloc(sizeof(x3widget));
  55. x3widget_init(result, type);
  56. result->name = name ? strdup(name) : NULL;
  57. result->var = x3carbonhiview;
  58. result->u.hiview = hiview;
  59. x3add(parent, result);
  60. x3qsizereq(result);
  61. return result;
  62. }
  63. static x3widget *x3widget_new_menu(x3widget *parent,
  64. const x3type *type,
  65. MenuRef menu)
  66. {
  67. x3widget *result = (x3widget *)malloc(sizeof(x3widget));
  68. x3widget_init(result, type);
  69. result->var = x3carbonmenu;
  70. result->u.menu = menu;
  71. x3add(parent, result);
  72. return result;
  73. }
  74. static x3widget *x3widget_new_menuitem(x3widget *parent,
  75. const x3type *type, int index)
  76. {
  77. x3widget *result = (x3widget *)malloc(sizeof(x3widget));
  78. x3widget_init(result, type);
  79. x3add(parent, result);
  80. result->var = x3carbonmenuitem;
  81. result->u.menuitem = index;
  82. return result;
  83. }
  84. void x3init(int *pargc, char ***pargv)
  85. {
  86. ProcessSerialNumber psn;
  87. /* Most apps get this done from loading the menu bar from the NIB.
  88. Prior to 10.3, there was an undocumented call. This one is official
  89. for 10.3 and later. */
  90. GetCurrentProcess(&psn);
  91. TransformProcessType(&psn, kProcessTransformToForegroundApplication);
  92. SetFrontProcess(&psn);
  93. x3initqs();
  94. }
  95. void x3main(void)
  96. {
  97. x3sync();
  98. RunApplicationEventLoop();
  99. }
  100. void x3_window_show(x3widget *mainwin)
  101. {
  102. ControlRef root;
  103. #if 0
  104. TransitionWindow(mainwin->u.window, kWindowZoomTransitionEffect,
  105. kWindowShowTransitionAction, NULL);
  106. #endif
  107. #if 0
  108. CreateRootControl(mainwin->u.window, &root);
  109. #endif
  110. //RepositionWindow(mainwin->u.window, NULL, kWindowCascadeOnMainScreen);
  111. ShowWindow(mainwin->u.window);
  112. SelectWindow(mainwin->u.window);
  113. }
  114. static WindowRef x3window_of(x3widget *w)
  115. {
  116. while (w->parent) w = w->parent;
  117. return w->var == x3carbonwindow ? w->u.window : NULL;
  118. }
  119. typedef struct {
  120. x3widget base;
  121. x3window_callback callback;
  122. void *callback_data;
  123. } x3widget_window;
  124. pascal OSStatus x3carbonWindowEventHandler(EventHandlerCallRef cr,
  125. EventRef inEvent, void *data)
  126. {
  127. x3widget_window *z = (x3widget_window *)data;
  128. OSStatus result = noErr;
  129. UInt32 eclass = GetEventClass(inEvent);
  130. UInt32 ekind = GetEventKind(inEvent);
  131. char multicharbuf[5];
  132. if (eclass == kEventClassCommand && ekind == kEventCommandProcess) {
  133. HICommand command;
  134. int status;
  135. GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand,
  136. NULL, sizeof(HICommand), NULL, &command);
  137. status = z->callback(&z->base, z->callback_data,
  138. x3multicharstr(command.commandID, multicharbuf),
  139. "command", NULL, NULL);
  140. if (status == 1)
  141. result = eventNotHandledErr;
  142. } else if (eclass = kEventClassWindow && ekind == kEventWindowBoundsChanged) {
  143. /* todo: only queue size request when size changes, not just pos */
  144. x3qsizereq(&z->base);
  145. x3sync();
  146. } else {
  147. printf("My handler is getting called %s %d!\n",
  148. x3multicharstr(eclass, multicharbuf),
  149. GetEventKind(inEvent));
  150. }
  151. result = eventNotHandledErr;
  152. return result;
  153. }
  154. void x3window_sizereq(x3widget *w)
  155. {
  156. }
  157. void x3window_sizealloc(x3widget *w, x3rect *r)
  158. {
  159. int i;
  160. Rect bounds;
  161. x3rect child_r;
  162. GetWindowBounds(w->u.window, kWindowContentRgn, &bounds);
  163. child_r.x0 = 0;
  164. child_r.x1 = bounds.right - bounds.left;
  165. child_r.y0 = 0;
  166. child_r.y1 = bounds.bottom - bounds.top;
  167. printf("x3window_sizealloc (%d, %d) - (%d, %d)\n",
  168. bounds.left, bounds.top, bounds.right, bounds.bottom);
  169. for (i = 0; i < w->n_children; i++) {
  170. x3widget *child = w->children[i];
  171. if (child->type->sizealloc)
  172. child->type->sizealloc(child, &child_r);
  173. child->flags &= ~x3flag_needsizealloc;
  174. }
  175. }
  176. x3type x3windowtype = { x3window_sizereq,
  177. x3window_sizealloc,
  178. x3add_default };
  179. x3widget *x3window(x3windowflags flags, char *label,
  180. x3window_callback callback, void *data)
  181. {
  182. WindowRef window;
  183. Rect bounds = { 100, 100, 400, 600 };
  184. EventHandlerRef handlerRef;
  185. WindowAttributes attrs =
  186. kWindowCompositingAttribute |
  187. kWindowLiveResizeAttribute |
  188. kWindowInWindowMenuAttribute |
  189. kWindowFrameworkScaledAttribute |
  190. kWindowStandardHandlerAttribute;
  191. EventTypeSpec windowEvents[] = {
  192. { kEventClassCommand, kEventCommandProcess },
  193. //{ kEventClassCommand, kEventCommandUpdateStatus },
  194. //{ kEventClassMouse, kEventMouseDown },
  195. //{ kEventClassWindow, kEventWindowClose },
  196. //{ kEventClassWindow, kEventWindowGetIdealSize },
  197. { kEventClassWindow, kEventWindowBoundsChanged },
  198. //{ kEventClassWindow, kEventWindowGetClickActivation },
  199. //{ kEventClassWindow, kEventWindowContextualMenuSelect }
  200. };
  201. CFStringRef cflabel = CFStringCreateWithCString(NULL, label,
  202. kCFStringEncodingUTF8);
  203. x3widget *result = (x3widget *)malloc(sizeof(x3widget_window));
  204. if (flags & x3window_main)
  205. attrs |= kWindowStandardDocumentAttributes;
  206. OSStatus err = CreateNewWindow(kDocumentWindowClass, attrs,
  207. &bounds, &window);
  208. SetWindowTitleWithCFString(window, cflabel);
  209. CFRelease(cflabel);
  210. x3widget_init(result, &x3windowtype);
  211. result->var = x3carbonwindow;
  212. result->u.window = window;
  213. ((x3widget_window *)result)->callback = callback;
  214. ((x3widget_window *)result)->callback_data = data;
  215. InstallWindowEventHandler(window, NewEventHandlerUPP(x3carbonWindowEventHandler),
  216. sizeof(windowEvents)/sizeof(EventTypeSpec),
  217. windowEvents, result, &handlerRef);
  218. x3qshow(result);
  219. return result;
  220. }
  221. x3type x3menutype = { NULL, NULL, x3add_default };
  222. x3widget *x3menu(x3widget *parent, char *name)
  223. {
  224. static int id = 1; /* Note: menu id should probably be kept per-window */
  225. MenuRef menu;
  226. CFStringRef cflabel = CFStringCreateWithCString(NULL, name,
  227. kCFStringEncodingUTF8);
  228. CreateNewMenu(id++, 0, &menu);
  229. SetMenuTitleWithCFString(menu, cflabel);
  230. CFRelease(cflabel);
  231. InsertMenu(menu, 0);
  232. return x3widget_new_menu(parent, &x3menutype, menu);
  233. }
  234. int x3parseshortcut(const char *shortcut, UInt16 *pkey, UInt8 *pmods)
  235. {
  236. UInt16 key;
  237. UInt8 mods = kMenuNoCommandModifier;
  238. int i = 0;
  239. while (shortcut[i] == '<') {
  240. if (!strncmp(shortcut + i, "<cmd>", 5)) {
  241. mods &= ~kMenuNoCommandModifier;
  242. i += 5;
  243. } else if (!strncmp(shortcut + i, "<shift>", 7)) {
  244. mods |= kMenuShiftModifier;
  245. i += 7;
  246. } else if (!strncmp(shortcut + i, "<option>", 8)) {
  247. mods |= kMenuOptionModifier;
  248. i += 8;
  249. } else if (!strncmp(shortcut + i, "<ctrl>", 6)) {
  250. mods |= kMenuControlModifier;
  251. i += 6;
  252. } else
  253. return false;
  254. }
  255. if (shortcut[i] && shortcut[i + 1] == 0) {
  256. key = shortcut[i];
  257. if (key >= 'a' && key <= 'z') key -= 'a' - 'A';
  258. else if (key >= 'A' && key <= 'Z') mods |= kMenuShiftModifier;
  259. } else
  260. return false;
  261. *pkey = key;
  262. *pmods = mods;
  263. return true;
  264. }
  265. x3type x3menuitemtype = { NULL, NULL, x3add_default };
  266. x3widget *x3menuitem(x3widget *parent, char *name, char *cmd, char *shortcut)
  267. {
  268. CFStringRef cflabel = CFStringCreateWithCString(NULL, name,
  269. kCFStringEncodingUTF8);
  270. MenuItemIndex index;
  271. AppendMenuItemTextWithCFString(parent->u.menu, cflabel,
  272. 0,
  273. x3mkmultichar(cmd), &index);
  274. if (shortcut) {
  275. UInt16 key;
  276. UInt8 mods;
  277. if (x3parseshortcut(shortcut, &key, &mods)) {
  278. SetMenuItemCommandKey(parent->u.menu, index, false, key);
  279. SetMenuItemModifiers(parent->u.menu, index, mods);
  280. }
  281. }
  282. CFRelease(cflabel);
  283. return x3widget_new_menuitem(parent, &x3menuitemtype, index);
  284. }
  285. x3widget *x3menusep(x3widget *parent)
  286. {
  287. Str255 str = {1, '-'};
  288. AppendMenu(parent->u.menu, str);
  289. return x3widget_new_menuitem(parent, &x3menuitemtype, -1);
  290. }
  291. void x3button_sizereq(x3widget *w)
  292. {
  293. SInt16 offset;
  294. Rect r = { 0, 0, 0, 0 };
  295. GetBestControlRect(w->u.hiview, &r, &offset);
  296. w->sizerequest.x0 = r.left;
  297. w->sizerequest.y0 = r.top;
  298. w->sizerequest.x1 = r.right;
  299. w->sizerequest.y1 = r.bottom;
  300. #ifdef VERBOSE
  301. printf("button sizereq = (%g, %g) - (%g, %g)\n",
  302. w->sizerequest.x0, w->sizerequest.y0,
  303. w->sizerequest.x1, w->sizerequest.y1);
  304. #endif
  305. }
  306. void x3button_sizealloc(x3widget *w, x3rect *r)
  307. {
  308. Rect bounds;
  309. bounds.left = r->x0;
  310. bounds.top = r->y0;
  311. bounds.right = r->x1;
  312. bounds.bottom = r->y1;
  313. /* TODO probably want to use HIViewSetFrame instead */
  314. printf("button sizealloc = (%g, %g) - (%g, %g)\n",
  315. r->x0, r->y0, r->x1, r->y1);
  316. SetControlBounds(w->u.hiview, &bounds);
  317. }
  318. x3type x3buttontype = { x3button_sizereq,
  319. x3button_sizealloc,
  320. x3add_default };
  321. x3widget *x3button(x3widget *parent, char *cmd, char *label)
  322. {
  323. WindowRef window = x3window_of(parent);
  324. Rect r = {10, 10, 30, 100};
  325. ControlRef control;
  326. OSStatus err;
  327. CFStringRef cflabel = CFStringCreateWithCString(NULL, label,
  328. kCFStringEncodingUTF8);
  329. err = CreatePushButtonControl(window, &r, cflabel, &control);
  330. CFRelease(cflabel);
  331. SetControlCommandID(control, x3mkmultichar(cmd));
  332. //SetWindowDefaultButton(window, control);
  333. return x3widget_new_hiview(parent, cmd, &x3buttontype, control);
  334. }
  335. x3widget *x3label(x3widget *parent, char *text)
  336. {
  337. WindowRef window = x3window_of(parent);
  338. Rect r = {10, 10, 30, 100};
  339. ControlRef control;
  340. OSStatus err;
  341. Boolean singleline = true;
  342. CFStringRef cftext = CFStringCreateWithCString(NULL, text,
  343. kCFStringEncodingUTF8);
  344. err = CreateStaticTextControl(window, &r, cftext,
  345. NULL, &control);
  346. CFRelease(cftext);
  347. #if 0
  348. SetControlData(control, kControlEntireControl,
  349. kControlEditTextSingleLineTag, sizeof(Boolean),
  350. &singleline);
  351. #endif
  352. return x3widget_new_hiview(parent, NULL, &x3buttontype, control);
  353. }
  354. x3widget *x3edittext(x3widget *parent, char *cmd)
  355. {
  356. WindowRef window = x3window_of(parent);
  357. Rect r = {10, 10, 30, 100};
  358. ControlRef control;
  359. OSStatus err;
  360. Boolean singleline = true;
  361. err = CreateEditUnicodeTextControl(window, &r, CFSTR(""),
  362. false, NULL, &control);
  363. SetControlCommandID(control, x3mkmultichar(cmd));
  364. #if 0
  365. SetControlData(control, kControlEntireControl,
  366. kControlEditTextSingleLineTag, sizeof(Boolean),
  367. &singleline);
  368. #endif
  369. return x3widget_new_hiview(parent, cmd, &x3buttontype, control);
  370. }
  371. x3widget *x3hpane(x3widget *parent)
  372. {
  373. return NULL;
  374. }
  375. x3widget *x3vpane(x3widget *parent)
  376. {
  377. return NULL;
  378. }
  379. typedef struct
  380. {
  381. HIViewRef view;
  382. x3viewflags flags;
  383. x3viewclient *vc;
  384. } x3view_data;
  385. static OSStatus
  386. x3view_construct(EventRef inEvent)
  387. {
  388. OSStatus err;
  389. x3view_data *data;
  390. data = (x3view_data *)malloc(sizeof(x3view_data));
  391. require_action(data != NULL, CantMalloc, err = memFullErr);
  392. err = GetEventParameter(inEvent, kEventParamHIObjectInstance,
  393. typeHIObjectRef, NULL, sizeof(HIObjectRef), NULL,
  394. (HIObjectRef *)&data->view);
  395. require_noerr(err, ParameterMissing);
  396. err = SetEventParameter(inEvent, kEventParamHIObjectInstance,
  397. typeVoidPtr, sizeof(x3view_data *), &data);
  398. data->vc = NULL;
  399. ParameterMissing:
  400. if (err != noErr)
  401. free(data);
  402. CantMalloc:
  403. return err;
  404. }
  405. static OSStatus
  406. x3view_destruct(EventRef inEvent, x3view_data *inData)
  407. {
  408. free(inData);
  409. return noErr;
  410. }
  411. static OSStatus
  412. x3view_initialize(EventHandlerCallRef inCallRef, EventRef inEvent,
  413. x3view_data *inData)
  414. {
  415. OSStatus err;
  416. HIRect bounds;
  417. err = CallNextEventHandler(inCallRef, inEvent);
  418. require_noerr(err, TroubleInSuperClass);
  419. err = GetEventParameter(inEvent, 'Boun', typeHIRect,
  420. NULL, sizeof(HIRect), NULL, &bounds);
  421. require_noerr(err, ParameterMissing);
  422. HIViewSetFrame(inData->view, &bounds);
  423. ParameterMissing:
  424. TroubleInSuperClass:
  425. return err;
  426. }
  427. static OSStatus
  428. x3view_draw(EventRef inEvent, x3view_data *inData)
  429. {
  430. OSStatus err;
  431. CGContextRef ctx;
  432. err = GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef,
  433. NULL, sizeof(CGContextRef), NULL, &ctx);
  434. require_noerr(err, ParameterMissing);
  435. #ifdef VERBOSE
  436. printf("x3view_draw!\n");
  437. #endif
  438. if (inData->vc && inData->vc->draw) {
  439. x3dc dc;
  440. /* set up bounds */
  441. if (inData->flags & x3view_2d) {
  442. dc.ctx = ctx;
  443. dc.path = NULL;
  444. dc.buf = NULL;
  445. inData->vc->draw(inData->vc, &dc);
  446. if (dc.path) {
  447. CGPathRelease(dc.path);
  448. }
  449. } else if (inData->flags & x3view_rgb) {
  450. /* todo */
  451. }
  452. }
  453. ParameterMissing:
  454. return err;
  455. }
  456. static OSStatus
  457. x3view_get_data(EventRef inEvent, x3view_data *inData)
  458. {
  459. OSStatus err;
  460. OSType tag;
  461. Ptr ptr;
  462. Size outSize;
  463. /* Probably could use a bit more error checking here, for type
  464. and size match. Also, just returning an x3view_data seems a
  465. little hacky. */
  466. err = GetEventParameter(inEvent, kEventParamControlDataTag, typeEnumeration,
  467. NULL, sizeof(OSType), NULL, &tag);
  468. require_noerr(err, ParameterMissing);
  469. err = GetEventParameter(inEvent, kEventParamControlDataBuffer, typePtr,
  470. NULL, sizeof(Ptr), NULL, &ptr);
  471. if (tag == kX3ViewPrivate) {
  472. *((x3view_data **)ptr) = inData;
  473. outSize = sizeof(x3view_data *);
  474. } else
  475. err = errDataNotSupported;
  476. if (err == noErr)
  477. err = SetEventParameter(inEvent, kEventParamControlDataBufferSize, typeLongInteger,
  478. sizeof(Size), &outSize);
  479. ParameterMissing:
  480. return err;
  481. }
  482. static OSStatus
  483. x3view_set_data(EventRef inEvent, x3view_data *inData)
  484. {
  485. OSStatus err;
  486. Ptr ptr;
  487. OSType tag;
  488. err = GetEventParameter(inEvent, kEventParamControlDataTag, typeEnumeration,
  489. NULL, sizeof(OSType), NULL, &tag);
  490. require_noerr(err, ParameterMissing);
  491. err = GetEventParameter(inEvent, kEventParamControlDataBuffer, typePtr,
  492. NULL, sizeof(Ptr), NULL, &ptr);
  493. require_noerr(err, ParameterMissing);
  494. if (tag == 'X3vc') {
  495. inData->vc = *(x3viewclient **)ptr;
  496. } else if (tag == 'X3vf') {
  497. inData->flags = *(x3viewflags *)ptr;
  498. } else
  499. err = errDataNotSupported;
  500. ParameterMissing:
  501. return err;
  502. }
  503. static OSStatus
  504. x3view_hittest(EventRef inEvent, x3view_data *inData)
  505. {
  506. OSStatus err;
  507. HIPoint where;
  508. HIRect bounds;
  509. ControlPartCode part;
  510. err = GetEventParameter(inEvent, kEventParamMouseLocation, typeHIPoint,
  511. NULL, sizeof(HIPoint), NULL, &where);
  512. require_noerr(err, ParameterMissing);
  513. err = HIViewGetBounds(inData->view, &bounds);
  514. require_noerr(err, ParameterMissing);
  515. if (CGRectContainsPoint(bounds, where))
  516. part = 1;
  517. else
  518. part = kControlNoPart;
  519. err = SetEventParameter(inEvent, kEventParamControlPart,
  520. typeControlPartCode, sizeof(ControlPartCode),
  521. &part);
  522. printf("hittest %g, %g!\n", where.x, where.y);
  523. ParameterMissing:
  524. return err;
  525. }
  526. /*
  527. If we need more sophisticated tracking (like mixing key events), there's
  528. a good discussion here:
  529. http://lists.apple.com/archives/Carbon-development/2001/Apr/msg01688.html
  530. */
  531. static OSStatus
  532. x3view_track(EventRef inEvent, x3view_data *inData)
  533. {
  534. OSStatus err;
  535. HIPoint where;
  536. MouseTrackingResult mouseStatus;
  537. HIRect bounds;
  538. Rect windBounds;
  539. Point theQDPoint;
  540. UInt32 mods;
  541. err = GetEventParameter(inEvent, kEventParamMouseLocation, typeHIPoint,
  542. NULL, sizeof(HIPoint), NULL, &where);
  543. require_noerr(err, ParameterMissing);
  544. err = GetEventParameter(inEvent, kEventParamKeyModifiers, typeUInt32,
  545. NULL, sizeof(UInt32), NULL, &mods);
  546. require_noerr(err, ParameterMissing);
  547. err = HIViewGetBounds(inData->view, &bounds);
  548. require_noerr(err, ParameterMissing);
  549. GetWindowBounds(GetControlOwner(inData->view), kWindowStructureRgn, &windBounds);
  550. if (inData->vc && inData->vc->mouse)
  551. inData->vc->mouse(inData->vc, 1, mods, where.x, where.y);
  552. #ifdef VERBOSE
  553. printf("press: %g, %g!\n", where.x, where.y);
  554. #endif
  555. //pe_view_button_press(inData, where.x, where.y, 0);
  556. mouseStatus = kMouseTrackingMouseDown;
  557. while (mouseStatus != kMouseTrackingMouseUp) {
  558. TrackMouseLocation(NULL, &theQDPoint, &mouseStatus);
  559. where.x = theQDPoint.h - windBounds.left;
  560. where.y = theQDPoint.v - windBounds.top;
  561. HIViewConvertPoint(&where, NULL, inData->view);
  562. #ifdef VERBOSE
  563. printf("track %d: %g, %g!\n", mouseStatus, where.x, where.y);
  564. #endif
  565. if (mouseStatus == kMouseTrackingMouseUp) {
  566. if (inData->vc && inData->vc->mouse)
  567. inData->vc->mouse(inData->vc, -1, mods, where.x, where.y);
  568. } else if (mouseStatus == kMouseTrackingKeyModifiersChanged) {
  569. mods = GetCurrentEventKeyModifiers();
  570. if (inData->vc && inData->vc->mouse)
  571. inData->vc->mouse(inData->vc, 0, mods, where.x, where.y);
  572. } else {
  573. if (inData->vc && inData->vc->mouse)
  574. inData->vc->mouse(inData->vc, 0, mods, where.x, where.y);
  575. }
  576. }
  577. ParameterMissing:
  578. return err;
  579. }
  580. pascal OSStatus
  581. x3view_handler(EventHandlerCallRef inCallRef,
  582. EventRef inEvent,
  583. void* inUserData )
  584. {
  585. OSStatus err = eventNotHandledErr;
  586. UInt32 eventClass = GetEventClass(inEvent);
  587. UInt32 eventKind = GetEventKind(inEvent);
  588. x3view_data *data = (x3view_data *)inUserData;
  589. printf("view handler %c%c%c%c %d\n",
  590. (eventClass >> 24) & 0xff,
  591. (eventClass >> 16) & 0xff,
  592. (eventClass >> 8) & 0xff,
  593. (eventClass >> 0) & 0xff,
  594. eventKind);
  595. switch (eventClass) {
  596. case kEventClassHIObject:
  597. switch (eventKind) {
  598. case kEventHIObjectConstruct:
  599. err = x3view_construct(inEvent);
  600. break;
  601. case kEventHIObjectInitialize:
  602. err = x3view_initialize(inCallRef, inEvent, data);
  603. break;
  604. case kEventHIObjectDestruct:
  605. err = x3view_destruct(inEvent, data);
  606. break;
  607. }
  608. break;
  609. case kEventClassControl:
  610. switch (eventKind) {
  611. case kEventControlInitialize:
  612. err = noErr;
  613. break;
  614. case kEventControlDraw:
  615. err = x3view_draw(inEvent, data);
  616. break;
  617. case kEventControlGetData:
  618. err = x3view_get_data(inEvent, data);
  619. break;
  620. case kEventControlSetData:
  621. err = x3view_set_data(inEvent, data);
  622. break;
  623. case kEventControlTrack:
  624. err = x3view_track(inEvent, data);
  625. break;
  626. case kEventControlHitTest:
  627. err = x3view_hittest(inEvent, data);
  628. break;
  629. case kEventControlClick:
  630. printf("click event\n");
  631. break;
  632. /*...*/
  633. }
  634. break;
  635. }
  636. return err;
  637. }
  638. static OSStatus
  639. x3view_register(void)
  640. {
  641. OSStatus err = noErr;
  642. static HIObjectClassRef x3view_ClassRef = NULL;
  643. if (x3view_ClassRef == NULL) {
  644. EventTypeSpec eventList[] = {
  645. { kEventClassHIObject, kEventHIObjectConstruct },
  646. { kEventClassHIObject, kEventHIObjectInitialize },
  647. { kEventClassHIObject, kEventHIObjectDestruct },
  648. { kEventClassControl, kEventControlActivate },
  649. { kEventClassControl, kEventControlDeactivate },
  650. { kEventClassControl, kEventControlDraw },
  651. { kEventClassControl, kEventControlHiliteChanged },
  652. { kEventClassControl, kEventControlHitTest },
  653. { kEventClassControl, kEventControlInitialize },
  654. { kEventClassControl, kEventControlGetData },
  655. { kEventClassControl, kEventControlSetData },
  656. { kEventClassControl, kEventControlTrack },
  657. { kEventClassControl, kEventControlClick }
  658. };
  659. err = HIObjectRegisterSubclass(kX3ViewClassID,
  660. kHIViewClassID,
  661. 0,
  662. x3view_handler,
  663. GetEventTypeCount(eventList),
  664. eventList,
  665. NULL,
  666. &x3view_ClassRef);
  667. }
  668. return err;
  669. }
  670. OSStatus x3view_create(
  671. WindowRef inWindow,
  672. const HIRect* inBounds,
  673. HIViewRef* outView)
  674. {
  675. OSStatus err;
  676. EventRef event;
  677. err = x3view_register();
  678. require_noerr(err, CantRegister);
  679. err = CreateEvent(NULL, kEventClassHIObject, kEventHIObjectInitialize,
  680. GetCurrentEventTime(), 0, &event);
  681. require_noerr(err, CantCreateEvent);
  682. if (inBounds != NULL) {
  683. err = SetEventParameter(event, 'Boun', typeHIRect, sizeof(HIRect),
  684. inBounds);
  685. require_noerr(err, CantSetParameter);
  686. }
  687. err = HIObjectCreate(kX3ViewClassID, event, (HIObjectRef*)outView);
  688. require_noerr(err, CantCreate);
  689. if (inWindow != NULL) {
  690. HIViewRef root;
  691. err = GetRootControl(inWindow, &root);
  692. require_noerr(err, CantGetRootView);
  693. err = HIViewAddSubview(root, *outView);
  694. }
  695. CantCreate:
  696. CantGetRootView:
  697. CantSetParameter:
  698. CantCreateEvent:
  699. ReleaseEvent(event);
  700. CantRegister:
  701. return err;
  702. }
  703. x3widget *x3view(x3widget *parent, x3viewflags flags, x3viewclient *vc)
  704. {
  705. WindowRef window = x3window_of(parent);
  706. HIRect r = { {10, 10}, {30, 100} };
  707. OSStatus err;
  708. HIViewRef view;
  709. err = x3view_create(window, &r, &view);
  710. err = SetControlData(view, 1, 'X3vc', sizeof(x3view_data *), &vc);
  711. err = SetControlData(view, 1, 'X3vf', sizeof(x3viewflags), &flags);
  712. HIViewSetVisible(view, true);
  713. return x3widget_new_hiview(parent, NULL, &x3buttontype, view);
  714. }
  715. void
  716. x3view_dirty(x3widget *w)
  717. {
  718. if (w->var == x3carbonhiview)
  719. HIViewSetNeedsDisplay(w->u.hiview, true);
  720. }
  721. void x3view_scrollto(x3widget *w, int x, int y, int width, int height)
  722. {
  723. /* todo */
  724. }
  725. void x3viewclient_init(x3viewclient *vc)
  726. {
  727. vc->destroy = NULL;
  728. vc->mouse = NULL;
  729. vc->key = NULL;
  730. vc->draw = NULL;
  731. }
  732. /* Functions for manipulating widget state - some fairly polymorphic. */
  733. void x3setactive(x3widget *w, int active)
  734. {
  735. if (w->var == x3carbonmenuitem) {
  736. MenuRef menu = w->parent->u.menu;
  737. if (active)
  738. EnableMenuItem(menu, w->u.menuitem);
  739. else
  740. DisableMenuItem(menu, w->u.menuitem);
  741. /* According to Carbon docs, we need to redraw menu. */
  742. } else if (w->var == x3carbonhiview) {
  743. if (active)
  744. ActivateControl(w->u.hiview);
  745. else
  746. DeactivateControl(w->u.hiview);
  747. }
  748. }
  749. int x3hasfocus(x3widget *w)
  750. {
  751. if (w->var == x3carbonhiview) {
  752. return HIViewSubtreeContainsFocus(w->u.hiview);
  753. } else
  754. return 0;
  755. }
  756. /* 2d drawing functions, implemented using Quartz */
  757. void
  758. x3moveto(x3dc *dc, double x, double y)
  759. {
  760. if (dc->path == NULL) {
  761. dc->path = CGPathCreateMutable();
  762. }
  763. CGPathMoveToPoint(dc->path, NULL, x, y);
  764. }
  765. void
  766. x3lineto(x3dc *dc, double x, double y)
  767. {
  768. CGPathAddLineToPoint(dc->path, NULL, x, y);
  769. }
  770. void
  771. x3curveto(x3dc *dc,
  772. double x1, double y1,
  773. double x2, double y2,
  774. double x3, double y3)
  775. {
  776. CGPathAddCurveToPoint(dc->path, NULL, x1, y1, x2, y2, x3, y3);
  777. }
  778. void
  779. x3closepath(x3dc *dc)
  780. {
  781. CGPathCloseSubpath(dc->path);
  782. }
  783. void
  784. x3rectangle(x3dc *dc, double x, double y, double width, double height)
  785. {
  786. CGRect rect;
  787. if (dc->path == NULL) {
  788. dc->path = CGPathCreateMutable();
  789. }
  790. rect.origin.x = x;
  791. rect.origin.y = y;
  792. rect.size.width = width;
  793. rect.size.height = height;
  794. CGPathAddRect(dc->path, NULL, rect);
  795. }
  796. void
  797. x3getcurrentpoint(x3dc *dc, double *px, double *py)
  798. {
  799. CGPoint point = CGPathGetCurrentPoint(dc->path);
  800. *px = point.x;
  801. *py = point.y;
  802. }
  803. void
  804. x3setrgba(x3dc *dc, unsigned int rgba)
  805. {
  806. CGContextSetRGBFillColor(dc->ctx,
  807. ((rgba >> 24) & 0xff) * (1.0/255),
  808. ((rgba >> 16) & 0xff) * (1.0/255),
  809. ((rgba >> 8) & 0xff) * (1.0/255),
  810. (rgba & 0xff) * (1.0/255));
  811. CGContextSetRGBStrokeColor(dc->ctx,
  812. ((rgba >> 24) & 0xff) * (1.0/255),
  813. ((rgba >> 16) & 0xff) * (1.0/255),
  814. ((rgba >> 8) & 0xff) * (1.0/255),
  815. (rgba & 0xff) * (1.0/255));
  816. }
  817. void
  818. x3setlinewidth(x3dc *dc, double w)
  819. {
  820. CGContextSetLineWidth(dc->ctx, w);
  821. }
  822. void
  823. x3fill(x3dc *dc)
  824. {
  825. CGContextAddPath(dc->ctx, dc->path);
  826. CGPathRelease(dc->path);
  827. dc->path = NULL;
  828. CGContextFillPath(dc->ctx);
  829. }
  830. void
  831. x3stroke(x3dc *dc)
  832. {
  833. CGContextAddPath(dc->ctx, dc->path);
  834. CGPathRelease(dc->path);
  835. dc->path = NULL;
  836. CGContextStrokePath(dc->ctx);
  837. }
  838. void
  839. x3selectfont(x3dc *dc, char *fontname, int slant, int weight)
  840. {
  841. CGContextSelectFont(dc->ctx, fontname, 8.0, kCGEncodingMacRoman);
  842. }
  843. void
  844. x3setfontsize(x3dc *dc, double size)
  845. {
  846. CGContextSetFontSize(dc->ctx, size);
  847. }
  848. void
  849. x3showtext(x3dc *dc, char *text)
  850. {
  851. CGPoint point = CGPathGetCurrentPoint(dc->path);
  852. CGAffineTransform textmat;
  853. textmat = CGAffineTransformMakeScale(1, -1);
  854. CGContextSetTextMatrix(dc->ctx, textmat);
  855. CGContextShowTextAtPoint(dc->ctx, point.x, point.y, text, strlen(text));
  856. }
  857. void x3textextents(x3dc *dc, char *text, x3extents *extents)
  858. {
  859. /* todo */
  860. }