forked from p-e-w/finalterm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUtilities.vala
191 lines (153 loc) · 6.15 KB
/
Utilities.vala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
* Copyright © 2013 Philipp Emanuel Weidmann <[email protected]>
*
* Nemo vir est qui mundum non reddat meliorem.
*
*
* This file is part of Final Term.
*
* Final Term is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Final Term is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Final Term. If not, see <http://www.gnu.org/licenses/>.
*/
// TODO: Make this a namespace?
public class Utilities : Object {
public static void initialize() {
scheduled_functions = new Gee.HashSet<string>();
}
// Returns the absolute path of a file that is given relative to another file
public static string get_absolute_filename(string filename, string relative_filename) {
return File.new_for_path(filename).get_parent().get_child(relative_filename).get_path();
}
public static Gee.Set<string> get_files_in_directory(string directory_name, string extension = "", bool recursive = false) {
var files = new Gee.HashSet<string>();
var directory = Dir.open(directory_name);
var pattern = new Regex(".*" + Regex.escape_string(extension) + "$", RegexCompileFlags.OPTIMIZE);
string filename;
while ((filename = directory.read_name()) != null) {
string path_name = Path.build_filename(directory_name, filename);
if (pattern.match(filename))
files.add(path_name);
if (recursive && FileUtils.test(path_name, FileTest.IS_DIR))
files.add_all(get_files_in_directory(path_name, extension, recursive));
}
return files;
}
public static Clutter.Color get_rgb_color(int red, int green, int blue) {
// TODO: A Vala bug prevents using this (linker error):
//return Clutter.Color().init((uint8)red, (uint8)green, (uint8)blue, 255);
var color = Clutter.Color();
color.red = (uint8)red;
color.green = (uint8)green;
color.blue = (uint8)blue;
color.alpha = 255;
return color;
}
// Returns a string representation of the specified color
// that can be parsed by the Pango markup parser
public static string get_parsable_color_string(Clutter.Color color) {
// Note that color.to_string() returns a string of the form "#rrggbbaa"
// while the Pango markup parser expects the form "#rrggbb"
return color.to_string().substring(0, 7);
}
public static void get_text_size(Pango.FontDescription font, string text, out int width, out int height) {
var dummy_label = new Gtk.Label(null);
dummy_label.override_font(font);
var layout = new Pango.Layout(dummy_label.get_pango_context());
layout.set_text(text, -1);
layout.get_pixel_size(out width, out height);
}
// TODO: Rename to "clamp" (cf. unichar)?
public static int bound_value(int value, int minimum, int maximum) {
if (value < minimum) {
return minimum;
} else if (value > maximum) {
return maximum;
} else {
return value;
}
}
public static T get_enum_value_from_name<T>(Type type, string name) {
EnumClass enum_class = (EnumClass)type.class_ref();
unowned EnumValue? enum_value = enum_class.get_value_by_name(name);
if (enum_value == null) {
warning("Invalid enum value name: '%s'", name);
return 0;
}
return (T)enum_value.value;
}
// TODO: These methods should of course use Json.Builder and Json.Reader;
// unfortunately, trying to employ those libraries resulted in multiple
// segmentation faults and other problems (Vala code generation issues?)
public static void save_list_to_file<T>(Gee.List<T> list, string filename) {
var file_stream = FileStream.open(filename, "w");
foreach (var item in list) {
var line = Json.gobject_to_data((Object)item, null);
line = line.replace("\n", "");
file_stream.puts(line + "\n");
}
file_stream.flush();
}
public static Gee.List<T>? load_list_from_file<T>(Type item_type, string filename) {
var file_stream = FileStream.open(filename, "r");
if (file_stream == null) {
warning("Error while opening file '%s' for reading", filename);
return null;
}
var list = new Gee.ArrayList<T>();
while (!file_stream.eof()) {
var line = file_stream.read_line();
if (line == null)
break;
T item = Json.gobject_from_data(item_type, line);
list.add(item);
}
return list;
}
public static void set_clipboard_text(Gtk.Widget widget, string text) {
var clipboard = Gtk.Clipboard.get_for_display(widget.get_display(), Gdk.SELECTION_CLIPBOARD);
clipboard.set_text(text, -1);
}
public static void get_actor_screen_position(GtkClutter.Embed clutter_embed, Clutter.Actor actor, out int x, out int y) {
// Position of parent window on screen
int window_x;
int window_y;
clutter_embed.get_parent_window().get_origin(out window_x, out window_y);
// Position of Clutter widget within parent window
// TODO: Is this always relative to the parent window?
Gtk.Allocation embed_allocation;
clutter_embed.get_allocation(out embed_allocation);
// Position of actor within Clutter widget (stage)
float actor_x;
float actor_y;
actor.get_transformed_position(out actor_x, out actor_y);
x = window_x + embed_allocation.x + (int)actor_x;
y = window_y + embed_allocation.y + (int)actor_y;
}
public delegate void ScheduleFunction();
private static Gee.Set<string> scheduled_functions;
// Executes function under the following contract:
// - function is guaranteed to be executed after at most interval milliseconds
// - If function is scheduled for execution again before it has been executed
// (as identified by function_name), function will only be executed once
public static void schedule_execution(ScheduleFunction function, string function_name, uint interval) {
if (scheduled_functions.contains(function_name))
// function already scheduled for execution
return;
scheduled_functions.add(function_name);
Timeout.add(interval, () => {
scheduled_functions.remove(function_name);
function();
return false;
});
}
}