1 /*
2  * Copyright (C) 2008-2009 David Robillard <d@drobilla.net>
3  * Copyright (C) 2017 Robin Gareus <robin@gareus.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #include <iostream>
21 #include <cairomm/context.h>
22 
23 #include "midi_scroomer.h"
24 #include "ui_config.h"
25 
26 using namespace Gtk;
27 using namespace std;
28 
29 //std::map<int, Glib::RefPtr<Gdk::Pixmap> > MidiScroomer::piano_pixmaps;
30 
MidiScroomer(Adjustment & adj)31 MidiScroomer::MidiScroomer(Adjustment& adj)
32 	: ArdourWidgets::Scroomer(adj)
33 {
34 
35 	adj.set_lower(0);
36 	adj.set_upper(127);
37 
38 	/* set minimum view range to one octave */
39 	set_min_page_size(12);
40 }
41 
~MidiScroomer()42 MidiScroomer::~MidiScroomer()
43 {
44 }
45 
46 bool
on_expose_event(GdkEventExpose * ev)47 MidiScroomer::on_expose_event(GdkEventExpose* ev)
48 {
49 	Cairo::RefPtr<Cairo::Context> cc = get_window()->create_cairo_context();
50 	GdkRectangle comp_rect, clip_rect;
51 	Component first_comp = point_in(ev->area.y);
52 	Component last_comp = point_in(ev->area.y + ev->area.height);
53 	int height = get_height();
54 	int lnote, hnote;
55 	double y2note = (double) 127 / height;
56 	double note2y = (double) height / 127;
57 	double note_width = 0.8 * get_width();
58 	double note_height = 1.4 * note2y;
59 	double black_shift = 0.1 * note2y;
60 	double colors[6] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
61 
62 	//cerr << ev->area.y << " " << ev->area.height << endl;
63 
64 	comp_rect.x = 0;
65 	comp_rect.width = get_width();
66 
67 	for (int i = first_comp; i <= last_comp; ++i) {
68 		Component comp = (Component) i;
69 		set_comp_rect(comp_rect, comp);
70 
71 		if (gdk_rectangle_intersect(&comp_rect, &ev->area, &clip_rect)) {
72 			get_colors(colors, comp);
73 
74 			cc->rectangle(clip_rect.x, clip_rect.y, clip_rect.width, clip_rect.height);
75 			cc->set_source_rgb (colors[3], colors[4], colors[5]);
76 			cc->fill_preserve();
77 			cc->clip();
78 
79 			cc->set_source_rgb(colors[0], colors[1], colors[2]);
80 			cc->set_line_width(note_height);
81 
82 			lnote = 127 - (int) floor((double) (clip_rect.y + clip_rect.height) * y2note) - 1;
83 			hnote = 127 - (int) floor((double) clip_rect.y * y2note) + 1;
84 
85 			for (int note = lnote; note < hnote + 1; ++note) {
86 				double y = height - note * note2y;
87 				bool draw = false;
88 
89 				switch (note % 12) {
90 				case 1:
91 				case 6:
92 					y -= black_shift;
93 					draw = true;
94 					break;
95 				case 3:
96 				case 10:
97 					y += black_shift;
98 					draw = true;
99 					break;
100 				case 8:
101 					draw = true;
102 					break;
103 				default:
104 					break;
105 				}
106 
107 				if(draw) {
108 					cc->set_line_width(1.4 * note2y);
109 					cc->move_to(0, y);
110 					cc->line_to(note_width, y);
111 					cc->stroke();
112 				}
113 			}
114 
115 			if (i == Handle1 || i == Handle2) {
116 				cc->rectangle(comp_rect.x + 0.5f, comp_rect.y + 0.5f, comp_rect.width - 1.0f, comp_rect.height - 1.0f);
117 				cc->set_line_width(1.0f);
118 				cc->set_source_rgb (1.0f, 1.0f, 1.0f);
119 				cc->stroke();
120 			}
121 
122 			cc->reset_clip();
123 		}
124 	}
125 
126 	return true;
127 }
128 
129 void
get_colors(double color[],Component comp)130 MidiScroomer::get_colors(double color[], Component comp)
131 {
132 	switch (comp) {
133 	case TopBase:
134 	case BottomBase:
135 		color[0] = 0.24f;
136 		color[1] = 0.24f;
137 		color[2] = 0.24f;
138 		color[3] = 0.33f;
139 		color[4] = 0.33f;
140 		color[5] = 0.33f;
141 		break;
142 	case Handle1:
143 	case Handle2:
144 		color[0] = 0.91f;
145 		color[1] = 0.91f;
146 		color[2] = 0.91f;
147 		color[3] = 0.0f;
148 		color[4] = 0.0f;
149 		color[5] = 0.0f;
150 		break;
151 	case Slider:
152 		color[0] = 0.38f;
153 		color[1] = 0.38f;
154 		color[2] = 0.38f;
155 		color[3] = 0.77f;
156 		color[4] = 0.77f;
157 		color[5] = 0.77f;
158 		break;
159 	default:
160 		break;
161 	}
162 }
163 
164 void
on_size_request(Gtk::Requisition * r)165 MidiScroomer::on_size_request(Gtk::Requisition* r)
166 {
167 	r->width = std::max (12.f, rintf (12.f * UIConfiguration::instance().get_ui_scale()));
168 }
169