GuiDrawingArea.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. /* GuiDrawingArea.cpp
  2. *
  3. * Copyright (C) 1993-2012,2013,2015,2016,2017 Paul Boersma,
  4. * 2008 Stefan de Konink, 2010 Franz Brausse, 2013 Tom Naughton
  5. *
  6. * This code is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or (at
  9. * your option) any later version.
  10. *
  11. * This code is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. * See the GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "GuiP.h"
  20. #if gtk
  21. #include "gdk/gdkkeysyms.h"
  22. #include <locale.h>
  23. #endif
  24. Thing_implement (GuiDrawingArea, GuiControl, 0);
  25. #if motif
  26. #define iam_drawingarea \
  27. Melder_assert (widget -> widgetClass == xmDrawingAreaWidgetClass); \
  28. GuiDrawingArea me = (GuiDrawingArea) widget -> userData
  29. #else
  30. #define iam_drawingarea \
  31. GuiDrawingArea me = (GuiDrawingArea) _GuiObject_getUserData (widget)
  32. #endif
  33. #if gtk
  34. static void _GuiGtkDrawingArea_destroyCallback (GuiObject widget, gpointer void_me) {
  35. (void) widget;
  36. iam (GuiDrawingArea);
  37. forget (me);
  38. }
  39. static gboolean _GuiGtkDrawingArea_exposeCallback (GuiObject widget, GdkEventExpose *expose, gpointer void_me) {
  40. trace (U"begin");
  41. iam (GuiDrawingArea);
  42. Melder_assert (me);
  43. // TODO: that helps against the damaged regions outside the rect where the
  44. // Graphics drawing is done, but where does that margin come from in the
  45. // first place?? Additionally this causes even more flickering
  46. //gdk_window_clear_area ((GTK_WIDGET (widget)) -> window, expose->area.x, expose->area.y, expose->area.width, expose->area.height);
  47. if (my d_exposeCallback) {
  48. struct structGuiDrawingArea_ExposeEvent event { me, 0 };
  49. event. x = expose -> area. x;
  50. event. y = expose -> area. y;
  51. event. width = expose -> area. width;
  52. event. height = expose -> area. height;
  53. try {
  54. //GdkRectangle rect = { event. x, event. y, event. width, event. height };
  55. //gdk_window_begin_paint_rect ((GTK_WIDGET (widget)) -> window, & rect);
  56. trace (U"send the expose callback");
  57. trace (U"locale is ", Melder_peek8to32 (setlocale (LC_ALL, nullptr)));
  58. my d_exposeCallback (my d_exposeBoss, & event);
  59. trace (U"the expose callback finished");
  60. trace (U"locale is ", Melder_peek8to32 (setlocale (LC_ALL, nullptr)));
  61. //gdk_window_end_paint ((GTK_WIDGET (widget)) -> window);
  62. //gdk_window_flush ((GTK_WIDGET (widget)) -> window);
  63. //gdk_flush ();
  64. } catch (MelderError) {
  65. Melder_flushError (U"Redrawing not completed");
  66. }
  67. trace (U"the expose callback handled drawing");
  68. return true;
  69. }
  70. trace (U"GTK will handle redrawing");
  71. return false;
  72. }
  73. static gboolean _GuiGtkDrawingArea_clickCallback (GuiObject widget, GdkEvent *e, gpointer void_me) {
  74. iam (GuiDrawingArea);
  75. if (e -> type != GDK_BUTTON_PRESS) return false;
  76. if (my d_clickCallback) {
  77. struct structGuiDrawingArea_ClickEvent event { me, 0 };
  78. event. button = ((GdkEventButton *) e) -> button;
  79. event. x = ((GdkEventButton *) e) -> x;
  80. event. y = ((GdkEventButton *) e) -> y;
  81. event. shiftKeyPressed = (((GdkEventButton *) e) -> state & GDK_SHIFT_MASK) != 0;
  82. event. commandKeyPressed = (((GdkEventButton *) e) -> state & GDK_CONTROL_MASK) != 0;
  83. event. optionKeyPressed = (((GdkEventButton *) e) -> state & GDK_MOD1_MASK) != 0;
  84. try {
  85. my d_clickCallback (my d_clickBoss, & event);
  86. } catch (MelderError) {
  87. Melder_flushError (U"Mouse click not completely handled.");
  88. }
  89. return true;
  90. }
  91. return false;
  92. }
  93. static gboolean _GuiGtkDrawingArea_keyCallback (GuiObject widget, GdkEvent *gevent, gpointer void_me) {
  94. iam (GuiDrawingArea);
  95. trace (U"begin");
  96. if (my d_keyCallback && gevent -> type == GDK_KEY_PRESS) {
  97. struct structGuiDrawingArea_KeyEvent event { me, 0 };
  98. GdkEventKey *gkeyEvent = (GdkEventKey *) gevent;
  99. event. key = gkeyEvent -> keyval;
  100. /*
  101. * Translate with the help of /usr/include/gtk-2.0/gdk/gdkkeysyms.h
  102. */
  103. if (event. key == GDK_KEY_Escape) event. key = 27;
  104. if (event. key == GDK_KEY_Left) event. key = 0x2190;
  105. if (event. key == GDK_KEY_Up) event. key = 0x2191;
  106. if (event. key == GDK_KEY_Right) event. key = 0x2192;
  107. if (event. key == GDK_KEY_Down) event. key = 0x2193;
  108. event. shiftKeyPressed = (gkeyEvent -> state & GDK_SHIFT_MASK) != 0;
  109. event. commandKeyPressed = (gkeyEvent -> state & GDK_CONTROL_MASK) != 0;
  110. event. optionKeyPressed = (gkeyEvent -> state & GDK_MOD1_MASK) != 0;
  111. event. extraControlKeyPressed = false;
  112. try {
  113. my d_keyCallback (my d_keyBoss, & event);
  114. } catch (MelderError) {
  115. Melder_flushError (U"Key press not completely handled.");
  116. }
  117. /*
  118. * FIXME: here we should empty the type-ahead buffer
  119. */
  120. return true;
  121. }
  122. return false; // if the drawing area has no keyCallback, the system will send the key press to a text field.
  123. }
  124. static gboolean _GuiGtkDrawingArea_resizeCallback (GuiObject widget, GtkAllocation *allocation, gpointer void_me) {
  125. iam (GuiDrawingArea);
  126. if (my d_resizeCallback) {
  127. struct structGuiDrawingArea_ResizeEvent event { me, 0 };
  128. trace (U"drawingArea resized to ", allocation -> width, U" x ", allocation -> height, U".");
  129. event. width = allocation -> width;
  130. event. height = allocation -> height;
  131. //g_debug("%d %d", allocation->width, allocation->height);
  132. try {
  133. my d_resizeCallback (my d_resizeBoss, & event);
  134. } catch (MelderError) {
  135. Melder_flushError (U"Window resizing not completely handled.");
  136. }
  137. return true;
  138. }
  139. return false;
  140. }
  141. #elif motif
  142. void _GuiWinDrawingArea_destroy (GuiObject widget) {
  143. iam_drawingarea;
  144. DestroyWindow (widget -> window);
  145. forget (me); // NOTE: my widget is not destroyed here
  146. }
  147. void _GuiWinDrawingArea_update (GuiObject widget) {
  148. iam_drawingarea;
  149. PAINTSTRUCT paintStruct;
  150. BeginPaint (widget -> window, & paintStruct);
  151. if (my d_exposeCallback) {
  152. struct structGuiDrawingArea_ExposeEvent event { me };
  153. try {
  154. my d_exposeCallback (my d_exposeBoss, & event);
  155. } catch (MelderError) {
  156. Melder_flushError (U"Redrawing not completed");
  157. }
  158. }
  159. EndPaint (widget -> window, & paintStruct);
  160. }
  161. void _GuiWinDrawingArea_handleClick (GuiObject widget, int x, int y) {
  162. iam_drawingarea;
  163. if (my d_clickCallback) {
  164. struct structGuiDrawingArea_ClickEvent event { me, 0 };
  165. event. x = x;
  166. event. y = y;
  167. event. shiftKeyPressed = GetKeyState (VK_SHIFT) < 0;
  168. event. optionKeyPressed = GetKeyState (VK_MENU) < 0;
  169. event. commandKeyPressed = GetKeyState (VK_CONTROL) < 0;
  170. try {
  171. my d_clickCallback (my d_clickBoss, & event);
  172. } catch (MelderError) {
  173. Melder_flushError (U"Mouse click not completely handled.");
  174. }
  175. }
  176. }
  177. void _GuiWinDrawingArea_handleKey (GuiObject widget, TCHAR kar) { // TODO: event?
  178. iam_drawingarea;
  179. if (my d_keyCallback) {
  180. struct structGuiDrawingArea_KeyEvent event { me, 0 };
  181. event. key = kar;
  182. if (event. key == VK_RETURN) event. key = 10;
  183. if (event. key == VK_LEFT) event. key = 0x2190;
  184. if (event. key == VK_RIGHT) event. key = 0x2192;
  185. if (event. key == VK_UP) event. key = 0x2191;
  186. if (event. key == VK_DOWN) event. key = 0x2193;
  187. event. shiftKeyPressed = GetKeyState (VK_SHIFT) < 0; // TODO: event -> key?
  188. event. optionKeyPressed = GetKeyState (VK_MENU) < 0;
  189. event. commandKeyPressed = GetKeyState (VK_CONTROL) < 0;
  190. try {
  191. my d_keyCallback (my d_keyBoss, & event);
  192. } catch (MelderError) {
  193. Melder_flushError (U"Key press not completely handled.");
  194. }
  195. }
  196. }
  197. void _GuiWinDrawingArea_shellResize (GuiObject widget) {
  198. iam_drawingarea;
  199. if (my d_resizeCallback) {
  200. struct structGuiDrawingArea_ResizeEvent event { me };
  201. event. width = widget -> width;
  202. event. height = widget -> height;
  203. try {
  204. my d_resizeCallback (my d_resizeBoss, & event);
  205. } catch (MelderError) {
  206. Melder_flushError (U"Window resizing not completely handled.");
  207. }
  208. }
  209. }
  210. #elif cocoa
  211. @interface GuiCocoaDrawingArea ()
  212. @property (nonatomic, assign) BOOL inited;
  213. @property (nonatomic, retain) NSTrackingArea *trackingArea;
  214. @end
  215. @implementation GuiCocoaDrawingArea {
  216. GuiDrawingArea d_userData;
  217. }
  218. - (id) initWithFrame: (NSRect) frame {
  219. self = [super initWithFrame: frame];
  220. if (self) {
  221. _trackingArea = [[[NSTrackingArea alloc]
  222. initWithRect: [self visibleRect]
  223. options: NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingInVisibleRect | NSTrackingActiveAlways
  224. owner: self
  225. userInfo: nil]
  226. autorelease];
  227. [self addTrackingArea: _trackingArea];
  228. }
  229. return self;
  230. }
  231. - (void) dealloc { // override
  232. GuiDrawingArea me = d_userData;
  233. forget (me);
  234. [self removeTrackingArea: _trackingArea];
  235. trace (U"deleting a drawing area");
  236. [super dealloc];
  237. }
  238. - (GuiThing) getUserData {
  239. return d_userData;
  240. }
  241. - (void) setUserData: (GuiThing) userData {
  242. d_userData = static_cast <GuiDrawingArea> (userData);
  243. }
  244. - (void) resizeCallback: (NSRect) rect {
  245. GuiDrawingArea me = (GuiDrawingArea) d_userData;
  246. if (me && my d_resizeCallback) {
  247. struct structGuiDrawingArea_ResizeEvent event = { me, 0, 0 };
  248. event. width = rect. size. width;
  249. event. height = rect. size. height;
  250. try {
  251. my d_resizeCallback (my d_resizeBoss, & event);
  252. } catch (MelderError) {
  253. Melder_flushError (U"Window resizing not completely handled.");
  254. }
  255. }
  256. }
  257. - (void) drawRect: (NSRect) dirtyRect {
  258. trace (U"dirtyRect: ", dirtyRect.origin.x, U", ", dirtyRect.origin.y, U", ", dirtyRect.size.width, U", ", dirtyRect.size.height);
  259. GuiDrawingArea me = (GuiDrawingArea) d_userData;
  260. if (! _inited) {
  261. // Last chance to do this. Is there a better place?
  262. [self resizeCallback: self. frame];
  263. _inited = YES;
  264. }
  265. if (my d_exposeCallback) {
  266. struct structGuiDrawingArea_ExposeEvent event = { me, 0, 0, 0, 0 };
  267. try {
  268. my d_exposeCallback (my d_exposeBoss, & event);
  269. } catch (MelderError) {
  270. Melder_flushError (U"Redrawing not completed");
  271. }
  272. }
  273. }
  274. - (void) setFrame: (NSRect) rect {
  275. [self resizeCallback: rect];
  276. [super setFrame: rect];
  277. }
  278. - (BOOL) acceptsFirstResponder {
  279. /*
  280. * This overridden method tells the event chain whether the drawing area can accept key events.
  281. * It is important that the Demo window and the RunnerMFC window accept key events.
  282. * A side effect of accepting key events is that the drawing area obtains the key focus when the user clicks in the drawing area.
  283. * It is important, however, that the drawing area of the TextGrid window cannot take away the key focus
  284. * from the text field at the top; therefore, that drawing area should not accept key events.
  285. * The implementation below is based on the fact that, naturally, the Demo window and the RunnerMFC window
  286. * have a key callback, and the drawing area of the TextGrid window has not
  287. * (a side effect of this implementation is that the drawing area of the Manual window does not take away
  288. * the key focus from the Search field, a situation that cannot hurt).
  289. */
  290. GuiDrawingArea me = (GuiDrawingArea) d_userData;
  291. return !! my d_keyCallback;
  292. }
  293. - (void) mouseEntered: (NSEvent *) nsEvent {
  294. (void) nsEvent;
  295. [[NSCursor crosshairCursor] push];
  296. }
  297. - (void) mouseExited: (NSEvent *) nsEvent{
  298. (void) nsEvent;
  299. [[NSCursor currentCursor] pop];
  300. }
  301. - (void) mouseDown: (NSEvent *) nsEvent {
  302. // [self becomeFirstResponder];
  303. GuiDrawingArea me = (GuiDrawingArea) d_userData;
  304. if (my d_clickCallback) {
  305. struct structGuiDrawingArea_ClickEvent event = { me, 0, 0, false, false, false, false, 0 };
  306. NSPoint local_point = [self convertPoint: [nsEvent locationInWindow] fromView: nil];
  307. event. x = local_point. x;
  308. //event. y = [self frame]. size. height - local_point. y;
  309. event. y = local_point. y;
  310. NSUInteger modifiers = [nsEvent modifierFlags];
  311. event. shiftKeyPressed = modifiers & NSShiftKeyMask;
  312. event. optionKeyPressed = modifiers & NSAlternateKeyMask;
  313. event. commandKeyPressed = modifiers & NSCommandKeyMask;
  314. try {
  315. my d_clickCallback (my d_clickBoss, & event);
  316. } catch (MelderError) {
  317. Melder_flushError (U"Mouse click not completely handled.");
  318. }
  319. }
  320. }
  321. - (void) scrollWheel: (NSEvent *) nsEvent {
  322. GuiDrawingArea me = (GuiDrawingArea) d_userData;
  323. if (my d_horizontalScrollBar || my d_verticalScrollBar) {
  324. if (my d_horizontalScrollBar) {
  325. GuiCocoaScrollBar *cocoaScrollBar = (GuiCocoaScrollBar *) my d_horizontalScrollBar -> d_widget;
  326. [cocoaScrollBar scrollBy: [nsEvent scrollingDeltaX]];
  327. }
  328. if (my d_verticalScrollBar) {
  329. GuiCocoaScrollBar *cocoaScrollBar = (GuiCocoaScrollBar *) my d_verticalScrollBar -> d_widget;
  330. [cocoaScrollBar scrollBy: [nsEvent scrollingDeltaY]];
  331. }
  332. } else {
  333. [super scrollWheel: nsEvent];
  334. }
  335. }
  336. - (void) magnifyWithEvent: (NSEvent *) nsEvent {
  337. GuiDrawingArea me = (GuiDrawingArea) d_userData;
  338. if (my d_horizontalScrollBar || my d_verticalScrollBar) {
  339. if (my d_horizontalScrollBar) {
  340. GuiCocoaScrollBar *cocoaScrollBar = (GuiCocoaScrollBar *) my d_horizontalScrollBar -> d_widget;
  341. [cocoaScrollBar magnifyBy: [nsEvent magnification]];
  342. }
  343. if (my d_verticalScrollBar) {
  344. GuiCocoaScrollBar *cocoaScrollBar = (GuiCocoaScrollBar *) my d_verticalScrollBar -> d_widget;
  345. [cocoaScrollBar magnifyBy: [nsEvent magnification]];
  346. }
  347. } else {
  348. [super magnifyWithEvent: nsEvent];
  349. }
  350. }
  351. - (BOOL) isFlipped {
  352. return YES;
  353. }
  354. - (void) keyDown: (NSEvent *) nsEvent {
  355. GuiDrawingArea me = (GuiDrawingArea) d_userData;
  356. if (my d_keyCallback) {
  357. struct structGuiDrawingArea_KeyEvent event = { me, U'\0', false, false, false, false };
  358. event. key = [[nsEvent charactersIgnoringModifiers] characterAtIndex: 0];
  359. if (event. key == NSLeftArrowFunctionKey) event. key = 0x2190;
  360. if (event. key == NSRightArrowFunctionKey) event. key = 0x2192;
  361. if (event. key == NSUpArrowFunctionKey) event. key = 0x2191;
  362. if (event. key == NSDownArrowFunctionKey) event. key = 0x2193;
  363. trace (U"key ", event. key);
  364. NSUInteger modifiers = [nsEvent modifierFlags];
  365. event. shiftKeyPressed = modifiers & NSShiftKeyMask;
  366. event. optionKeyPressed = modifiers & NSAlternateKeyMask;
  367. event. commandKeyPressed = modifiers & NSCommandKeyMask;
  368. try {
  369. my d_keyCallback (my d_keyBoss, & event);
  370. } catch (MelderError) {
  371. Melder_flushError (U"Key press not completely handled.");
  372. }
  373. }
  374. }
  375. @end
  376. #endif
  377. #if gtk
  378. static gboolean _guiGtkDrawingArea_swipeCallback (GuiObject w, GdkEventScroll *event, gpointer void_me) {
  379. iam (GuiDrawingArea);
  380. if (my d_horizontalScrollBar) {
  381. double hv = gtk_range_get_value (GTK_RANGE (my d_horizontalScrollBar -> d_widget));
  382. GtkAdjustment *adjustment = gtk_range_get_adjustment (GTK_RANGE (my d_horizontalScrollBar -> d_widget));
  383. gdouble hi;
  384. g_object_get (adjustment, "step_increment", & hi, nullptr);
  385. switch (event -> direction) {
  386. case GDK_SCROLL_LEFT:
  387. gtk_range_set_value (GTK_RANGE (my d_horizontalScrollBar -> d_widget), hv - hi);
  388. break;
  389. case GDK_SCROLL_RIGHT:
  390. gtk_range_set_value (GTK_RANGE (my d_horizontalScrollBar -> d_widget), hv + hi);
  391. break;
  392. }
  393. }
  394. if (my d_verticalScrollBar) {
  395. double vv = gtk_range_get_value (GTK_RANGE (my d_verticalScrollBar -> d_widget));
  396. GtkAdjustment *adjustment = gtk_range_get_adjustment (GTK_RANGE (my d_verticalScrollBar -> d_widget));
  397. gdouble vi;
  398. g_object_get (adjustment, "step_increment", & vi, nullptr);
  399. switch (event -> direction) {
  400. case GDK_SCROLL_UP:
  401. gtk_range_set_value (GTK_RANGE (my d_verticalScrollBar -> d_widget), vv - vi);
  402. break;
  403. case GDK_SCROLL_DOWN:
  404. gtk_range_set_value (GTK_RANGE (my d_verticalScrollBar -> d_widget), vv + vi);
  405. break;
  406. }
  407. }
  408. return true;
  409. }
  410. #endif
  411. GuiDrawingArea GuiDrawingArea_create (GuiForm parent, int left, int right, int top, int bottom,
  412. GuiDrawingArea_ExposeCallback exposeCallback,
  413. GuiDrawingArea_ClickCallback clickCallback,
  414. GuiDrawingArea_KeyCallback keyCallback,
  415. GuiDrawingArea_ResizeCallback resizeCallback, Thing boss,
  416. uint32 /* flags */)
  417. {
  418. autoGuiDrawingArea me = Thing_new (GuiDrawingArea);
  419. my d_shell = parent -> d_shell;
  420. my d_parent = parent;
  421. my d_exposeCallback = exposeCallback;
  422. my d_exposeBoss = boss;
  423. my d_clickCallback = clickCallback;
  424. my d_clickBoss = boss;
  425. my d_keyCallback = keyCallback;
  426. my d_keyBoss = boss;
  427. my d_resizeCallback = resizeCallback;
  428. my d_resizeBoss = boss;
  429. #if gtk
  430. my d_widget = gtk_drawing_area_new ();
  431. GdkEventMask mask = (GdkEventMask) (GDK_EXPOSURE_MASK // receive exposure events
  432. | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK // receive click events
  433. | GDK_BUTTON_MOTION_MASK // receive motion notifies when a button is pressed
  434. | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK
  435. | GDK_POINTER_MOTION_HINT_MASK); // receive fewer motion notify events (the cb might take time)
  436. gtk_widget_set_events (GTK_WIDGET (my d_widget), mask);
  437. g_signal_connect (G_OBJECT (my d_widget), "expose-event", G_CALLBACK (_GuiGtkDrawingArea_exposeCallback), me.get());
  438. g_signal_connect (G_OBJECT (my d_widget), "destroy", G_CALLBACK (_GuiGtkDrawingArea_destroyCallback), me.get());
  439. g_signal_connect (G_OBJECT (my d_widget), "button-press-event", G_CALLBACK (_GuiGtkDrawingArea_clickCallback), me.get());
  440. g_signal_connect (G_OBJECT (my d_widget), "button-release-event", G_CALLBACK (_GuiGtkDrawingArea_clickCallback), me.get());
  441. g_signal_connect (G_OBJECT (my d_widget), "motion-notify-event", G_CALLBACK (_GuiGtkDrawingArea_clickCallback), me.get());
  442. if (parent) {
  443. Melder_assert (parent -> d_widget);
  444. g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (GTK_WIDGET (parent -> d_widget))), "key-press-event",
  445. G_CALLBACK (_GuiGtkDrawingArea_keyCallback), me.get());
  446. }
  447. g_signal_connect (G_OBJECT (my d_widget), "size-allocate", G_CALLBACK (_GuiGtkDrawingArea_resizeCallback), me.get());
  448. _GuiObject_setUserData (my d_widget, me.get());
  449. my v_positionInForm (my d_widget, left, right, top, bottom, parent);
  450. gtk_widget_set_double_buffered (GTK_WIDGET (my d_widget), false);
  451. #elif motif
  452. my d_widget = _Gui_initializeWidget (xmDrawingAreaWidgetClass, parent -> d_widget, U"drawingArea");
  453. _GuiObject_setUserData (my d_widget, me.get());
  454. my d_widget -> window = CreateWindowEx (0, Melder_peek32toW (_GuiWin_getDrawingAreaClassName ()), L"drawingArea",
  455. WS_CHILD | WS_BORDER | WS_CLIPSIBLINGS,
  456. my d_widget -> x, my d_widget -> y, my d_widget -> width, my d_widget -> height, my d_widget -> parent -> window, nullptr, theGui.instance, nullptr);
  457. SetWindowLongPtr (my d_widget -> window, GWLP_USERDATA, (LONG_PTR) my d_widget);
  458. my v_positionInForm (my d_widget, left, right, top, bottom, parent);
  459. #elif cocoa
  460. GuiCocoaDrawingArea *drawingArea = [[GuiCocoaDrawingArea alloc] init];
  461. my d_widget = (GuiObject) drawingArea;
  462. my v_positionInForm (my d_widget, left, right, top, bottom, parent);
  463. [drawingArea setUserData: me.get()];
  464. if (keyCallback) {
  465. [[drawingArea window] makeFirstResponder: drawingArea]; // needed in DemoWindow
  466. }
  467. #endif
  468. return me.releaseToAmbiguousOwner();
  469. }
  470. GuiDrawingArea GuiDrawingArea_createShown (GuiForm parent, int left, int right, int top, int bottom,
  471. GuiDrawingArea_ExposeCallback exposeCallback,
  472. GuiDrawingArea_ClickCallback clickCallback,
  473. GuiDrawingArea_KeyCallback keyCallback,
  474. GuiDrawingArea_ResizeCallback resizeCallback, Thing boss,
  475. uint32 flags)
  476. {
  477. GuiDrawingArea me = GuiDrawingArea_create (parent, left, right, top, bottom, exposeCallback, clickCallback, keyCallback, resizeCallback, boss, flags);
  478. GuiThing_show (me);
  479. return me;
  480. }
  481. GuiDrawingArea GuiDrawingArea_create (GuiScrolledWindow parent, int width, int height,
  482. GuiDrawingArea_ExposeCallback exposeCallback,
  483. GuiDrawingArea_ClickCallback clickCallback,
  484. GuiDrawingArea_KeyCallback keyCallback,
  485. GuiDrawingArea_ResizeCallback resizeCallback, Thing boss,
  486. uint32 /* flags */)
  487. {
  488. autoGuiDrawingArea me = Thing_new (GuiDrawingArea);
  489. my d_shell = parent -> d_shell;
  490. my d_parent = parent;
  491. my d_exposeCallback = exposeCallback;
  492. my d_exposeBoss = boss;
  493. my d_clickCallback = clickCallback;
  494. my d_clickBoss = boss;
  495. my d_keyCallback = keyCallback;
  496. my d_keyBoss = boss;
  497. my d_resizeCallback = resizeCallback;
  498. my d_resizeBoss = boss;
  499. #if gtk
  500. my d_widget = gtk_drawing_area_new ();
  501. GdkEventMask mask = (GdkEventMask) (GDK_EXPOSURE_MASK // receive exposure events
  502. | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK // receive click events
  503. | GDK_BUTTON_MOTION_MASK // receive motion notifies when a button is pressed
  504. | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK
  505. | GDK_POINTER_MOTION_HINT_MASK); // receive fewer motion notify events (the cb might take time)
  506. gtk_widget_set_events (GTK_WIDGET (my d_widget), mask);
  507. g_signal_connect (G_OBJECT (my d_widget), "expose-event", G_CALLBACK (_GuiGtkDrawingArea_exposeCallback), me.get());
  508. g_signal_connect (G_OBJECT (my d_widget), "destroy", G_CALLBACK (_GuiGtkDrawingArea_destroyCallback), me.get());
  509. g_signal_connect (G_OBJECT (my d_widget), "button-press-event", G_CALLBACK (_GuiGtkDrawingArea_clickCallback), me.get());
  510. g_signal_connect (G_OBJECT (my d_widget), "button-release-event", G_CALLBACK (_GuiGtkDrawingArea_clickCallback), me.get());
  511. g_signal_connect (G_OBJECT (my d_widget), "motion-notify-event", G_CALLBACK (_GuiGtkDrawingArea_clickCallback), me.get());
  512. if (parent) {
  513. g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (GTK_WIDGET (parent -> d_widget))), "key-press-event",
  514. G_CALLBACK (_GuiGtkDrawingArea_keyCallback), me.get());
  515. }
  516. g_signal_connect (G_OBJECT (my d_widget), "size-allocate", G_CALLBACK (_GuiGtkDrawingArea_resizeCallback), me.get());
  517. _GuiObject_setUserData (my d_widget, me.get());
  518. my v_positionInScrolledWindow (my d_widget, width, height, parent);
  519. gtk_widget_set_double_buffered (GTK_WIDGET (my d_widget), false);
  520. #elif motif
  521. my d_widget = _Gui_initializeWidget (xmDrawingAreaWidgetClass, parent -> d_widget, U"drawingArea");
  522. _GuiObject_setUserData (my d_widget, me.get());
  523. my d_widget -> window = CreateWindowEx (0, Melder_peek32toW (_GuiWin_getDrawingAreaClassName ()), L"drawingArea",
  524. WS_CHILD | WS_BORDER | WS_CLIPSIBLINGS,
  525. 0, 0, my d_widget -> width, my d_widget -> height, my d_widget -> parent -> window, nullptr, theGui.instance, nullptr);
  526. SetWindowLongPtr (my d_widget -> window, GWLP_USERDATA, (LONG_PTR) my d_widget);
  527. my v_positionInScrolledWindow (my d_widget, width, height, parent);
  528. #elif cocoa
  529. GuiCocoaDrawingArea *drawingArea = [[GuiCocoaDrawingArea alloc] init];
  530. my d_widget = (GuiObject) drawingArea;
  531. my v_positionInScrolledWindow (my d_widget, width, height, parent);
  532. [drawingArea setUserData: me.get()];
  533. #endif
  534. return me.releaseToAmbiguousOwner();
  535. }
  536. GuiDrawingArea GuiDrawingArea_createShown (GuiScrolledWindow parent, int width, int height,
  537. GuiDrawingArea_ExposeCallback exposeCallback,
  538. GuiDrawingArea_ClickCallback clickCallback,
  539. GuiDrawingArea_KeyCallback keyCallback,
  540. GuiDrawingArea_ResizeCallback resizeCallback, Thing boss,
  541. uint32 flags)
  542. {
  543. GuiDrawingArea me = GuiDrawingArea_create (parent, width, height, exposeCallback, clickCallback, keyCallback, resizeCallback, boss, flags);
  544. GuiThing_show (me);
  545. return me;
  546. }
  547. void GuiDrawingArea_setSwipable (GuiDrawingArea me, GuiScrollBar horizontalScrollBar, GuiScrollBar verticalScrollBar) {
  548. my d_horizontalScrollBar = horizontalScrollBar;
  549. my d_verticalScrollBar = verticalScrollBar;
  550. #if gtk
  551. g_signal_connect (G_OBJECT (my d_widget), "scroll-event", G_CALLBACK (_guiGtkDrawingArea_swipeCallback), me);
  552. #endif
  553. }
  554. void GuiDrawingArea_setExposeCallback (GuiDrawingArea me, GuiDrawingArea_ExposeCallback callback, Thing boss) {
  555. my d_exposeCallback = callback;
  556. my d_exposeBoss = boss;
  557. }
  558. void GuiDrawingArea_setClickCallback (GuiDrawingArea me, GuiDrawingArea_ClickCallback callback, Thing boss) {
  559. my d_clickCallback = callback;
  560. my d_clickBoss = boss;
  561. }
  562. void GuiDrawingArea_setResizeCallback (GuiDrawingArea me, GuiDrawingArea_ResizeCallback callback, Thing boss) {
  563. my d_resizeCallback = callback;
  564. my d_resizeBoss = boss;
  565. }
  566. /* End of file GuiDrawingArea.cpp */