1 /*
2  * Copyright (C) 2010-2012 Carl Hetherington <carl@carlh.net>
3  * Copyright (C) 2012-2015 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2014-2017 Robin Gareus <robin@gareus.org>
5  *
6  * This program 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
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include <gdkmm/cursor.h>
22 
23 #include "gtkmm2ext/cursors.h"
24 
25 #include "utils.h"
26 #include "mouse_cursors.h"
27 #include "editor_xpms"
28 
29 using namespace ARDOUR_UI_UTILS;
30 
31 Gdk::Cursor* MouseCursors::_invalid = 0;
32 
MouseCursors()33 MouseCursors::MouseCursors ()
34 	: cross_hair (0)
35 	, scissors (0)
36 	, trimmer (0)
37 	, right_side_trim (0)
38 	, anchored_right_side_trim (0)
39 	, left_side_trim (0)
40 	, anchored_left_side_trim (0)
41 	, right_side_trim_left_only (0)
42 	, left_side_trim_right_only (0)
43 	, fade_in (0)
44 	, fade_out (0)
45 	, selector (0)
46 	, grabber (0)
47 	, grabber_note (0)
48 	, zoom_in (0)
49 	, zoom_out (0)
50 	, time_fx (0)
51 	, fader (0)
52 	, speaker (0)
53 	, midi_pencil (0)
54 	, midi_select (0)
55 	, midi_resize (0)
56 	, midi_erase (0)
57 	, up_down (0)
58 	, wait (0)
59 	, timebar (0)
60 	, transparent (0)
61 	, resize_left (0)
62 	, resize_top_left (0)
63 	, resize_top (0)
64 	, resize_top_right (0)
65 	, resize_right (0)
66 	, resize_bottom_right (0)
67 	, resize_bottom (0)
68 	, resize_bottom_left (0)
69 	, move (0)
70 	, expand_left_right (0)
71 	, expand_up_down (0)
72 {
73 }
74 
~MouseCursors()75 MouseCursors::~MouseCursors ()
76 {
77 	drop_all ();
78 }
79 
80 void
drop_all()81 MouseCursors::drop_all ()
82 {
83 	delete cross_hair; cross_hair = 0;
84 	delete scissors; scissors = 0;
85 	delete trimmer; trimmer = 0;
86 	delete right_side_trim; right_side_trim = 0;
87 	delete anchored_right_side_trim; anchored_right_side_trim = 0;
88 	delete left_side_trim; left_side_trim = 0;
89 	delete anchored_left_side_trim; anchored_left_side_trim = 0;
90 	delete right_side_trim_left_only; right_side_trim_left_only = 0;
91 	delete left_side_trim_right_only; left_side_trim_right_only = 0;
92 	delete fade_in; fade_in = 0;
93 	delete fade_out; fade_out = 0;
94 	delete selector; selector = 0;
95 	delete grabber; grabber = 0;
96 	delete grabber_note; grabber_note = 0;
97 	delete zoom_in; zoom_in = 0;
98 	delete zoom_out; zoom_out = 0;
99 	delete time_fx; time_fx = 0;
100 	delete fader; fader = 0;
101 	delete speaker; speaker = 0;
102 	delete midi_pencil; midi_pencil = 0;
103 	delete midi_select; midi_select = 0;
104 	delete midi_resize; midi_resize = 0;
105 	delete midi_erase; midi_erase = 0;
106 	delete up_down; up_down = 0;
107 	delete wait; wait = 0;
108 	delete timebar; timebar = 0;
109 	delete transparent; transparent = 0;
110 	delete resize_left; resize_left = 0;
111 	delete resize_top_left; resize_top_left = 0;
112 	delete resize_top; resize_top = 0;
113 	delete resize_top_right; resize_top_right = 0;
114 	delete resize_right; resize_right = 0;
115 	delete resize_bottom_right; resize_bottom_right = 0;
116 	delete resize_bottom; resize_bottom = 0;
117 	delete resize_bottom_left; resize_bottom_left = 0;
118 	delete move; move = 0;
119 	delete expand_left_right; expand_left_right = 0;
120 	delete expand_up_down; expand_up_down = 0;
121 }
122 
123 Gdk::Cursor*
make_cursor(const char * name,int hotspot_x,int hotspot_y)124 MouseCursors::make_cursor (const char* name, int hotspot_x, int hotspot_y)
125 {
126 	Gtkmm2ext::CursorInfo* info = Gtkmm2ext::CursorInfo::lookup_cursor_info (name);
127 
128 	if (info) {
129 		hotspot_x = info->x;
130 		hotspot_y = info->y;
131 	}
132 
133 	Glib::RefPtr<Gdk::Pixbuf> p (::get_icon (name, _cursor_set));
134 	return new Gdk::Cursor (Gdk::Display::get_default(), p, hotspot_x, hotspot_y);
135 }
136 
137 void
set_cursor_set(const std::string & name)138 MouseCursors::set_cursor_set (const std::string& name)
139 {
140 	using namespace Glib;
141 	using namespace Gdk;
142 
143 	drop_all ();
144 	Gtkmm2ext::CursorInfo::drop_cursor_info();
145 	_cursor_set = name;
146 
147 	std::string hotspot_info_path = get_icon_path ("hotspots", _cursor_set, false);
148 
149 	if (!hotspot_info_path.empty()) {
150 		Gtkmm2ext::CursorInfo::load_cursor_info (hotspot_info_path);
151 	}
152 
153 	/* these will throw exceptions if their images cannot be found.
154 
155 	   the default hotspot coordinates will be overridden by any
156 	   data found by Gtkmm2ext::Cursors::load_cursor_info(). the values
157 	   here from the set of cursors used by Ardour; new cursor/icon
158 	   sets should come with a hotspot info file.
159 	*/
160 
161 	zoom_in = make_cursor ("zoom_in_cursor", 10, 5);
162 	zoom_out = make_cursor ("zoom_out_cursor", 5, 5);
163 	scissors = make_cursor ("scissors", 5, 0);
164 	grabber = make_cursor ("grabber", 5, 0);
165 	grabber_note = make_cursor ("grabber_note", 5, 10);
166 	left_side_trim = make_cursor ("trim_left_cursor", 5, 11);
167 	anchored_left_side_trim = make_cursor ("anchored_trim_left_cursor", 5, 11);
168 	right_side_trim = make_cursor ("trim_right_cursor", 23, 11);
169 	anchored_right_side_trim = make_cursor ("anchored_trim_right_cursor", 23, 11);
170 	left_side_trim_right_only = make_cursor ("trim_left_cursor_right_only", 5, 11);
171 	right_side_trim_left_only = make_cursor ("trim_right_cursor_left_only", 23, 11);
172 	fade_in = make_cursor ("fade_in_cursor", 0, 0);
173 	fade_out = make_cursor ("fade_out_cursor", 29, 0);
174 	resize_left = make_cursor ("resize_left_cursor", 3, 10);
175 	resize_top_left = make_cursor ("resize_top_left_cursor", 3, 3);
176 	resize_top = make_cursor ("resize_top_cursor", 10, 3);
177 	resize_top_right = make_cursor ("resize_top_right_cursor", 18, 3);
178 	resize_right = make_cursor ("resize_right_cursor", 24, 10);
179 	resize_bottom_right = make_cursor ("resize_bottom_right_cursor", 18, 18);
180 	resize_bottom = make_cursor ("resize_bottom_cursor", 10, 24);
181 	resize_bottom_left = make_cursor ("resize_bottom_left_cursor", 3, 18);
182 	move = make_cursor ("move_cursor", 11, 11);
183 	expand_left_right = make_cursor ("expand_left_right_cursor", 11, 4);
184 	expand_up_down = make_cursor ("expand_up_down_cursor", 4, 11);
185 	selector = make_cursor ("i_beam_cursor", 4, 11);
186 
187 	Gdk::Color fbg ("#ffffff");
188 	Gdk::Color ffg ("#000000");
189 
190 	{
191 		RefPtr<Bitmap> source = Bitmap::create ((char const *) fader_cursor_bits, fader_cursor_width, fader_cursor_height);
192 		RefPtr<Bitmap> mask = Bitmap::create ((char const *) fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
193 		fader = new Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
194 	}
195 
196 	{
197 		RefPtr<Bitmap> source = Bitmap::create ((char const *) speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
198 		RefPtr<Bitmap> mask = Bitmap::create ((char const *) speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
199 		speaker = new Cursor (source, mask, ffg, fbg, speaker_cursor_width >> 1, speaker_cursor_height >> 1);
200 	}
201 
202 	{
203 		char pix[4] = { 0, 0, 0, 0 };
204 		RefPtr<Bitmap> bits = Bitmap::create (pix, 2, 2);
205 		Color c;
206 		transparent = new Cursor (bits, bits, c, c, 0, 0);
207 	}
208 
209 	cross_hair = new Cursor (CROSSHAIR);
210 	trimmer =  new Cursor (SB_H_DOUBLE_ARROW);
211 	time_fx = new Cursor (SIZING);
212 	wait = new Cursor (WATCH);
213 	timebar = new Cursor(LEFT_PTR);
214 	midi_pencil = new Cursor (PENCIL);
215 	midi_select = new Cursor (CENTER_PTR);
216 	midi_resize = new Cursor (SIZING);
217 	midi_erase = new Cursor (DRAPED_BOX);
218 	up_down = new Cursor (SB_V_DOUBLE_ARROW);
219 }
220 
221 void
create_invalid()222 MouseCursors::create_invalid()
223 {
224 	char pix[4] = { 0, 0, 0, 0 };
225 	Glib::RefPtr<Gdk::Bitmap> bits = Gdk::Bitmap::create (pix, 2, 2);
226 	Gdk::Color c;
227 	_invalid = new Gdk::Cursor (bits, bits, c, c, 0, 0);
228 }
229