Assists music production by grouping standalone programs into sessions. Community version of "Non Session Manager".
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.

879 lines
18KB

  1. /*******************************************************************************/
  2. /* Copyright (C) 2007-2008 Jonathan Moore Liles */
  3. /* */
  4. /* This program is free software; you can redistribute it and/or modify it */
  5. /* under the terms of the GNU General Public License as published by the */
  6. /* Free Software Foundation; either version 2 of the License, or (at your */
  7. /* option) any later version. */
  8. /* */
  9. /* This program is distributed in the hope that it will be useful, but WITHOUT */
  10. /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
  11. /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
  12. /* more details. */
  13. /* */
  14. /* You should have received a copy of the GNU General Public License along */
  15. /* with This program; see the file COPYING. If not,write to the Free Software */
  16. /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  17. /*******************************************************************************/
  18. /* This is a generic double-buffering, optimizing canvas interface to
  19. grids (patterns and phrases). It draws only what is necessary to keep
  20. the display up-to-date. Actual drawing functions are in draw.C */
  21. #include "canvas.H"
  22. #include "pattern.H"
  23. #include "gui/draw.H"
  24. #include "common.h"
  25. #include "non.H"
  26. cell_t **
  27. Canvas::_alloc_array ( void )
  28. {
  29. cell_t **a;
  30. int one = sizeof( typeof( a ) ) * m.vp->w;
  31. int two = sizeof( typeof( a[0] ) ) * (m.vp->h * m.vp->w);
  32. a = (cell_t **) malloc( one + two );
  33. m.size = one + two;
  34. cell_t *c = (cell_t *) (((unsigned char *)a) + one);
  35. for ( uint x = m.vp->w; x-- ; )
  36. {
  37. a[x] = c;
  38. c += m.vp->h;
  39. for ( uint y = m.vp->h; y-- ; )
  40. {
  41. a[ x ][ y ].flags = 0;
  42. a[ x ][ y ].state = -1;
  43. a[ x ][ y ].shape = SQUARE;
  44. a[ x ][ y ].color = 0;
  45. }
  46. }
  47. m.w = m.vp->w;
  48. m.h = m.vp->h;
  49. return a;
  50. }
  51. Canvas::Canvas ( )
  52. {
  53. m.height = m.width = m.div_w = m.div_h = m.playhead = m.margin_top = m.margin_left = m.playhead = m.w = m.h = m.p1 = m.p2 = 0;
  54. m.margin_top = ruler_height;
  55. m.ruler_drawn = false;
  56. m.mapping_drawn = false;
  57. m.grid_drawn = false;
  58. m.current = m.previous = NULL;
  59. m.row_compact = true;
  60. m.maxh = 128;
  61. m.vp = NULL;
  62. }
  63. void
  64. Canvas::handle_event_change ( void )
  65. {
  66. /* mark the song as dirty and pass the signal on */
  67. song.dirty( true );
  68. signal_draw();
  69. }
  70. /** change grid to /g/, returns TRUE if new grid size differs from old */
  71. void
  72. Canvas::grid ( Grid *g )
  73. {
  74. m.grid = g;
  75. if ( ! g )
  76. return;
  77. m.vp = &g->viewport;
  78. char *s = m.vp->dump();
  79. DEBUG( "viewport: %s", s );
  80. free( s );
  81. m.ruler_drawn = false;
  82. resize_grid();
  83. changed_mapping();
  84. m.shape = m.grid->draw_shape();
  85. /* connect signals */
  86. /* FIXME: what happens when we do this twice? */
  87. g->signal_events_change.connect( mem_fun( this, &Canvas::handle_event_change ) );
  88. g->signal_settings_change.connect( signal_settings_change.make_slot() );
  89. signal_draw();
  90. signal_settings_change();
  91. }
  92. /** keep row compaction tables up-to-date */
  93. void
  94. Canvas::_update_row_mapping ( void )
  95. {
  96. /* reset */
  97. for ( int i = 128; i-- ; )
  98. m.rtn[i] = m.ntr[i] = -1;
  99. DEBUG( "updating row mapping" );
  100. /* rebuild */
  101. int r = 0;
  102. for ( int n = 0; n < 128; ++n )
  103. {
  104. if ( m.grid->row_name( n ) )
  105. {
  106. m.rtn[r] = n;
  107. m.ntr[n] = r;
  108. ++r;
  109. }
  110. }
  111. if ( m.row_compact && r )
  112. m.maxh = r;
  113. else
  114. m.maxh = 128;
  115. m.vp->h = min( m.vp->h, m.maxh );
  116. }
  117. /** change grid mapping */
  118. void
  119. Canvas::changed_mapping ( void )
  120. {
  121. _update_row_mapping();
  122. m.mapping_drawn = false;
  123. m.vp->y = (m.maxh / 2) - (m.vp->h / 2);
  124. resize();
  125. int old_margin = m.margin_left;
  126. m.margin_left = 0;
  127. m.draw = false;
  128. m.grid->draw_row_names( this );
  129. if ( m.margin_left != old_margin )
  130. signal_resize();
  131. else
  132. signal_draw();
  133. }
  134. Grid *
  135. Canvas::grid ( void )
  136. {
  137. return m.grid;
  138. }
  139. /** recalculate node sizes based on physical dimensions */
  140. void
  141. Canvas::resize ( void )
  142. {
  143. if ( ! m.vp )
  144. return;
  145. m.div_w = (m.width - m.margin_left) / m.vp->w;
  146. m.div_h = (m.height - m.margin_top) / m.vp->h;
  147. m.border_w = min( m.div_w, m.div_h ) / 8;
  148. m.mapping_drawn = m.ruler_drawn = false;
  149. }
  150. /** reallocate buffers to match grid dimensions */
  151. void
  152. Canvas::resize_grid ( void )
  153. {
  154. // _update_row_mapping();
  155. resize();
  156. if ( m.vp )
  157. {
  158. if ( m.vp->w != m.w || m.vp->h != m.h ||
  159. m.div_w != m.old_div_w || m.div_h != m.old_div_h )
  160. {
  161. if ( m.grid_drawn )
  162. signal_resize();
  163. m.old_div_w = m.div_w;
  164. m.old_div_h = m.div_h;
  165. }
  166. else
  167. return;
  168. }
  169. DEBUG( "resizing grid %dx%d", m.vp->w, m.vp->h );
  170. if ( m.previous )
  171. {
  172. free( m.previous );
  173. free( m.current );
  174. }
  175. m.current = _alloc_array();
  176. m.previous = _alloc_array();
  177. m.grid_drawn = false;
  178. }
  179. /** inform the canvas with new phsyical dimensions */
  180. void
  181. Canvas::resize ( int x, int y, int w, int h )
  182. {
  183. m.origin_x = x;
  184. m.origin_y = y;
  185. m.width = w;
  186. m.height = h;
  187. resize();
  188. }
  189. /***********/
  190. /* Drawing */
  191. /***********/
  192. /** copy last buffer into current */
  193. void
  194. Canvas::copy ( void )
  195. {
  196. for ( uint y = m.vp->h; y-- ; )
  197. for ( uint x = m.vp->w; x-- ; )
  198. m.current[ x ][ y ] = m.previous[ x ][ y ];
  199. }
  200. /** reset last buffer */
  201. void
  202. Canvas::_reset ( void )
  203. {
  204. cell_t empty;
  205. for ( uint y = m.vp->h; y-- ; )
  206. for ( uint x = m.vp->w; x-- ; )
  207. m.current[ x ][ y ] = empty;
  208. }
  209. /** prepare current buffer for drawing (draw "background") */
  210. void
  211. Canvas::clear ( void )
  212. {
  213. uint rule = m.grid->ppqn();
  214. uint lx = m.grid->ts_to_x( m.grid->length() );
  215. for ( uint y = m.vp->h; y--; )
  216. for ( uint x = m.vp->w; x--; )
  217. {
  218. m.current[ x ][ y ].color = 0;
  219. m.current[ x ][ y ].shape = m.shape;
  220. m.current[ x ][ y ].state = EMPTY;
  221. m.current[ x ][ y ].flags = 0;
  222. }
  223. for ( int x = m.vp->w - rule; x >= 0; x -= rule )
  224. for ( uint y = m.vp->h; y-- ; )
  225. m.current[ x ][ y ].state = LINE;
  226. int sx = (int)(lx - m.vp->x) >= 0 ? lx - m.vp->x : 0;
  227. for ( int x = sx; x < m.vp->w; ++x )
  228. for ( int y = m.vp->h; y-- ; )
  229. m.current[ x ][ y ].state = PARTIAL;
  230. }
  231. /** is /x/ within the viewport? */
  232. bool
  233. Canvas::viewable_x ( int x )
  234. {
  235. return x >= m.vp->x && x < m.vp->x + m.vp->w;
  236. }
  237. /** flush delta of last and current buffers to screen, then flip them */
  238. void
  239. Canvas::flip ( void )
  240. {
  241. /* FIXME: should this not go in clear()? */
  242. if ( m.p1 != m.p2 )
  243. {
  244. if ( viewable_x( m.p1 ) ) draw_line( m.p1 - m.vp->x, F_P1 );
  245. if ( viewable_x( m.p2 ) ) draw_line( m.p2 - m.vp->x, F_P2 );
  246. }
  247. if ( viewable_x( m.playhead ) ) draw_line( m.playhead - m.vp->x, F_PLAYHEAD );
  248. for ( uint y = m.vp->h; y--; )
  249. for ( uint x = m.vp->w; x--; )
  250. {
  251. cell_t *c = &m.current[ x ][ y ];
  252. cell_t *p = &m.previous[ x ][ y ];
  253. if ( *c != *p )
  254. gui_draw_shape( m.origin_x + m.margin_left + x * m.div_w, m.origin_y + m.margin_top + y * m.div_h, m.div_w, m.div_h, m.border_w,
  255. c->shape, c->state, c->flags, c->color );
  256. }
  257. cell_t **tmp = m.previous;
  258. m.previous = m.current;
  259. m.current = tmp;
  260. }
  261. /** redraw the ruler at the top of the canvas */
  262. void
  263. Canvas::redraw_ruler ( void )
  264. {
  265. m.margin_top = gui_draw_ruler( m.origin_x + m.margin_left, m.origin_y, m.vp->w, m.div_w, m.grid->division(), m.vp->x,
  266. m.p1 - m.vp->x, m.p2 - m.vp->x );
  267. m.ruler_drawn = true;
  268. }
  269. /** callback called by Grid::draw_row_names() to draw an individual row name */
  270. void
  271. Canvas::draw_row_name ( int y, const char *name, int color )
  272. {
  273. bool draw = m.draw;
  274. bool clear = false;
  275. y = ntr( y );
  276. if ( ! m.row_compact && ! name )
  277. clear = true;
  278. y -= m.vp->y;
  279. int bx = m.origin_x;
  280. int by = m.origin_y + m.margin_top + y * m.div_h;
  281. int bw = min( m.margin_left, m.width / 8 );
  282. int bh = m.div_h;
  283. if ( y < 0 || y >= m.vp->h )
  284. draw = false;
  285. if ( clear && draw )
  286. gui_clear_area( bx, by, bw, bh );
  287. else
  288. m.margin_left = max( m.margin_left, gui_draw_string( bx, by,
  289. bw, bh,
  290. color,
  291. name,
  292. draw ) );
  293. }
  294. /** redraw row names */
  295. void
  296. Canvas::redraw_mapping ( void )
  297. {
  298. m.margin_left = 0;
  299. m.draw = false;
  300. m.grid->draw_row_names( this );
  301. resize();
  302. m.draw = true;
  303. m.grid->draw_row_names( this );
  304. m.mapping_drawn = true;
  305. }
  306. void
  307. Canvas::draw_mapping ( void )
  308. {
  309. if ( ! m.mapping_drawn ) redraw_mapping();
  310. }
  311. void
  312. Canvas::draw_ruler ( void )
  313. {
  314. if ( ! m.ruler_drawn ) redraw_ruler();
  315. }
  316. /** "draw" a shape in the backbuffer */
  317. void
  318. Canvas::draw_shape ( int x, int y, int shape, int state, int color, bool selected )
  319. {
  320. y = ntr( y );
  321. if ( y < 0 )
  322. return;
  323. // adjust for viewport.
  324. x -= m.vp->x;
  325. y -= m.vp->y;
  326. if ( x < 0 || y < 0 || x >= m.vp->w || y >= m.vp->h )
  327. return;
  328. m.current[ x ][ y ].shape = shape;
  329. m.current[ x ][ y ].color = color;
  330. m.current[ x ][ y ].state = (uint)m.vp->x + x > m.grid->ts_to_x( m.grid->length() ) ? PARTIAL : state;
  331. m.current[ x ][ y ].flags = selected ? F_SELECTED : 0;
  332. }
  333. /** callback used by Grid::draw() */
  334. void
  335. Canvas::draw_dash ( int x, int y, int l, int shape, int color, bool selected )
  336. {
  337. draw_shape( x, y, shape, FULL, color, selected );
  338. for ( int i = x + l - 1; i > x; i-- )
  339. {
  340. draw_shape( i, y, shape, CONTINUED, 0, selected );
  341. }
  342. }
  343. /** draw a vertical line with flags */
  344. void
  345. Canvas::draw_line ( int x, int flags )
  346. {
  347. for ( uint y = m.vp->h; y-- ; )
  348. m.current[ x ][ y ].flags |= flags;
  349. }
  350. /** draw only the playhead--without reexamining the grid */
  351. int
  352. Canvas::draw_playhead ( void )
  353. {
  354. int x = m.grid->ts_to_x( m.grid->index() );
  355. if ( m.playhead == x )
  356. return 0;
  357. m.playhead = x;
  358. if ( m.playhead < m.vp->x || m.playhead >= m.vp->x + m.vp->w )
  359. {
  360. if ( config.follow_playhead )
  361. {
  362. m.vp->x = m.playhead / m.vp->w * m.vp->w;
  363. m.ruler_drawn = false;
  364. signal_draw();
  365. return 0;
  366. }
  367. }
  368. copy();
  369. for ( uint x = m.vp->w; x-- ; )
  370. for ( uint y = m.vp->h; y-- ; )
  371. m.current[ x ][ y ].flags &= ~ (F_PLAYHEAD | F_P1 | F_P2 );
  372. flip();
  373. return 1;
  374. }
  375. /** draw ONLY those nodes necessary to bring the canvas up-to-date with the grid */
  376. void
  377. Canvas::draw ( void )
  378. {
  379. DEBUG( "drawing canvas" );
  380. draw_mapping();
  381. draw_ruler();
  382. m.grid_drawn = true;
  383. m.grid->draw( this, m.vp->x, m.vp->y, m.vp->w, m.vp->h );
  384. }
  385. /** redraw every node on the canvas from the buffer (without
  386. * necessarily reexamining the grid) */
  387. void
  388. Canvas::redraw ( void )
  389. {
  390. DEBUG( "redrawing canvas" );
  391. if ( ! m.grid_drawn )
  392. draw();
  393. m.ruler_drawn = false;
  394. m.mapping_drawn = false;
  395. draw_mapping();
  396. draw_ruler();
  397. for ( int y = m.vp->h; y--; )
  398. for ( int x = m.vp->w; x--; )
  399. {
  400. cell_t c = m.previous[ x ][ y ];
  401. if ( c.shape > HEXAGON ) return;
  402. if ( m.vp->x + x == m.playhead )
  403. c.flags |= F_PLAYHEAD;
  404. gui_draw_shape( m.origin_x + m.margin_left + x * m.div_w, m.origin_y + m.margin_top + y * m.div_h, m.div_w, m.div_h, m.border_w,
  405. c.shape, c.state, c.flags, c.color );
  406. }
  407. }
  408. /** convert pixel coords into grid coords. returns true if valid */
  409. bool
  410. Canvas::grid_pos ( int *x, int *y ) const
  411. {
  412. *y = (*y - m.margin_top - m.origin_y) / m.div_h;
  413. *x = (*x - m.margin_left - m.origin_x) / m.div_w;
  414. if ( *x < 0 || *y < 0 || *x >= m.vp->w || *y >= m.vp->h )
  415. return false;
  416. /* adjust for viewport */
  417. *x += m.vp->x;
  418. *y += m.vp->y;
  419. /* adjust for row-compaction */
  420. *y = rtn( *y );
  421. return true;
  422. }
  423. /******************/
  424. /* Input handlers */
  425. /******************/
  426. /* These methods translate viewport pixel coords to absolute grid
  427. coords and pass on to the grid. */
  428. /** if coords correspond to a row name entry, return the (absolute) note number, otherwise return -1 */
  429. int
  430. Canvas::is_row_name ( int x, int y )
  431. {
  432. if ( x - m.origin_x >= m.margin_left )
  433. return -1;
  434. x = m.margin_left;
  435. grid_pos( &x, &y );
  436. return m.grid->y_to_note( y );
  437. }
  438. void
  439. Canvas::set ( int x, int y )
  440. {
  441. if ( y - m.origin_y < m.margin_top )
  442. /* looks like a click on the ruler */
  443. {
  444. if ( x - m.margin_left - m.origin_x >= 0 )
  445. {
  446. m.p1 = m.vp->x + ((x - m.margin_left - m.origin_x) / m.div_w);
  447. m.ruler_drawn = false;
  448. }
  449. _lr();
  450. signal_draw();
  451. return;
  452. }
  453. if ( ! grid_pos( &x, &y ) )
  454. return;
  455. m.grid->put( x, y, 0 );
  456. }
  457. void
  458. Canvas::unset ( int x, int y )
  459. {
  460. if ( y - m.origin_y < m.margin_top )
  461. /* looks like a click on the ruler */
  462. {
  463. if ( x - m.margin_left - m.origin_x >= 0 )
  464. {
  465. m.p2 = m.vp->x + ((x - m.margin_left - m.origin_x) / m.div_w);
  466. m.ruler_drawn = false;
  467. }
  468. _lr();
  469. signal_draw();
  470. return;
  471. }
  472. if ( ! grid_pos( &x, &y ) )
  473. return;
  474. m.grid->del( x, y );
  475. }
  476. void
  477. Canvas::adj_color ( int x, int y, int n )
  478. {
  479. if ( ! grid_pos( &x, &y ) )
  480. return;
  481. m.grid->adj_velocity( x, y, n );
  482. }
  483. void
  484. Canvas::adj_length ( int x, int y, int n )
  485. {
  486. if ( ! grid_pos( &x, &y ) )
  487. return;
  488. m.grid->adj_duration( x, y, n );
  489. }
  490. void
  491. Canvas::select ( int x, int y )
  492. {
  493. if ( ! grid_pos( &x, &y ) )
  494. return;
  495. m.grid->select( x, y, true );
  496. }
  497. void
  498. Canvas::move_selected ( int dir, int n )
  499. {
  500. switch ( dir )
  501. {
  502. case RIGHT:
  503. m.grid->move_selected( n );
  504. break;
  505. case LEFT:
  506. m.grid->move_selected( 0 - n );
  507. break;
  508. case UP:
  509. case DOWN:
  510. {
  511. /* row-compaction makes this a little complicated */
  512. event_list *el = m.grid->events();
  513. /* FIXME: don't allow movement beyond the edges! */
  514. /* int hi, lo; */
  515. /* m.grid->selected_hi_lo_note( &hi, &lo ); */
  516. /* hi = ntr( hi ) > 0 ? ntr( hi ) : */
  517. /* if ( m.grid->y_to_note( ntr( hi ) ) ) */
  518. if ( dir == UP )
  519. for ( int y = 0; y <= m.maxh; ++y )
  520. el->rewrite_selected( m.grid->y_to_note( rtn( y ) ), m.grid->y_to_note( rtn( y - n ) ) );
  521. else
  522. for ( int y = m.maxh; y >= 0; --y )
  523. el->rewrite_selected( m.grid->y_to_note( rtn( y ) ), m.grid->y_to_note( rtn( y + n ) ) );
  524. m.grid->events( el );
  525. delete el;
  526. break;
  527. }
  528. }
  529. }
  530. void
  531. Canvas::randomize_row ( int y )
  532. {
  533. int x = m.margin_left;
  534. if ( ! grid_pos( &x, &y ) )
  535. return;
  536. ((pattern*)m.grid)->randomize_row( y, song.random.feel, song.random.probability );
  537. }
  538. void
  539. Canvas::_lr ( void )
  540. {
  541. int l, r;
  542. if ( m.p2 > m.p1 )
  543. {
  544. l = m.p1;
  545. r = m.p2;
  546. }
  547. else
  548. {
  549. l = m.p2;
  550. r = m.p1;
  551. }
  552. m.p1 = l;
  553. m.p2 = r;
  554. }
  555. void
  556. Canvas::select_range ( void )
  557. {
  558. m.grid->select( m.p1, m.p2 );
  559. }
  560. void
  561. Canvas::crop ( void )
  562. {
  563. m.grid->crop( m.p1, m.p2 );
  564. m.vp->x = 0;
  565. m.p2 = m.p2 - m.p1;
  566. m.p1 = 0;
  567. m.ruler_drawn = false;
  568. }
  569. void
  570. Canvas::delete_time ( void )
  571. {
  572. m.grid->delete_time( m.p1, m.p2 );
  573. }
  574. void
  575. Canvas::insert_time ( void )
  576. {
  577. m.grid->insert_time( m.p1, m.p2 );
  578. }
  579. /** paste range as new grid */
  580. void
  581. Canvas::duplicate_range ( void )
  582. {
  583. Grid *g = m.grid->clone();
  584. g->crop( m.p1, m.p2 );
  585. g->viewport.x = 0;
  586. }
  587. void
  588. Canvas::row_compact ( int n )
  589. {
  590. switch ( n )
  591. {
  592. case OFF:
  593. m.row_compact = false;
  594. m.maxh = 128;
  595. break;
  596. case ON:
  597. m.row_compact = true;
  598. m.vp->y = 0;
  599. _update_row_mapping();
  600. break;
  601. case TOGGLE:
  602. row_compact( m.row_compact ? OFF : ON );
  603. break;
  604. }
  605. _reset();
  606. m.mapping_drawn = false;
  607. }
  608. void
  609. Canvas::pan ( int dir, int n )
  610. {
  611. switch ( dir )
  612. {
  613. case LEFT: case RIGHT: case TO_PLAYHEAD: case TO_NEXT_NOTE: case TO_PREV_NOTE:
  614. /* handle horizontal movement specially */
  615. n *= m.grid->division();
  616. m.ruler_drawn = false;
  617. break;
  618. default:
  619. n *= 5;
  620. m.mapping_drawn = false;
  621. break;
  622. }
  623. switch ( dir )
  624. {
  625. case LEFT:
  626. m.vp->x = max( m.vp->x - n, 0 );
  627. break;
  628. case RIGHT:
  629. m.vp->x += n;
  630. break;
  631. case TO_PLAYHEAD:
  632. m.vp->x = m.playhead - (m.playhead % m.grid->division());
  633. break;
  634. case UP:
  635. m.vp->y = max( m.vp->y - n, 0 );
  636. break;
  637. case DOWN:
  638. m.vp->y = min( m.vp->y + n, m.maxh - m.vp->h );
  639. break;
  640. case TO_NEXT_NOTE:
  641. {
  642. int x = m.grid->next_note_x( m.vp->x );
  643. m.vp->x = x - (x % m.grid->division() );
  644. break;
  645. }
  646. case TO_PREV_NOTE:
  647. {
  648. int x = m.grid->prev_note_x( m.vp->x );
  649. m.vp->x = x - (x % m.grid->division() );
  650. break;
  651. }
  652. }
  653. signal_draw();
  654. }
  655. /** adjust horizontal zoom (* n) */
  656. void
  657. Canvas::h_zoom ( float n )
  658. {
  659. m.vp->w = max( 32, min( (int)(m.vp->w * n), 256 ) );
  660. resize_grid();
  661. }
  662. /** adjust vertical zoom (* n) */
  663. void
  664. Canvas::v_zoom ( float n )
  665. {
  666. m.vp->h = max( 1, min( (int)(m.vp->h * n), m.maxh ) );
  667. resize_grid();
  668. }
  669. void
  670. Canvas::notes ( char *s )
  671. {
  672. m.grid->notes( s );
  673. }
  674. char *
  675. Canvas::notes ( void )
  676. {
  677. return m.grid->notes();
  678. }