Archive
/
/
/
/
/
Echo.UI.Widgets.PlaySourceView.vala
2008-12-02 06:48:35 UTC
previous
next
/* vim: set noexpandtab tabstop=4 shiftwidth=4 nowrap textwidth=100
*
* Echo Media Player
* Copyright (C) 2008 Shane O'Connell
*
* [ The original file includes a copyright header in this location describing
* the file as being released under the terms of the GNU General Public
* License. It has been removed in order to display the file as part of the
* archive. ]
*/
using Echo.Core;
using Echo.Interfaces;
using Echo.Tools;
using Echo.UI;
using Echo.UI.TreeModels;
public class Echo.UI.Widgets.PlaySourceView : Gtk.ScrolledWindow
{
private PlaySourceModel _treemodel;
private Gtk.TreeView _treeview;
private ContextMenu _context_menu;
public ContextMenu context_menu { get { return _context_menu; } }
private IPlaySource _source;
public IPlaySource source { get { return _source; } }
private IModPlaySource _mod_source = null;
public signal void delete_pressed();
public PlaySourceView(IPlaySource source)
{
_source = source;
if (_source is IModPlaySource)
_mod_source = (IModPlaySource)_source;
this.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
this.set_shadow_type(Gtk.ShadowType.IN);
_treemodel = new PlaySourceModel(_source);
_treeview = new Gtk.TreeView.with_model(_treemodel);
_treeview.set_rules_hint(true);
_treeview.set_fixed_height_mode(true);
_treeview.row_activated += (treeview, path, column) => {
Services.playback().play(_source.get_track(_treemodel.get_index_from_path(path)));
};
_treeview.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE);
if (_mod_source != null) {
_treeview.key_press_event += (treeview, event) => {
int GDK_Delete = 0xffff;
int GDK_KP_Delete = 0xff9f;
if (event.keyval == GDK_Delete || event.keyval == GDK_KP_Delete)
delete_pressed();;
};
}
init_dnd();
init_columns();
init_context_menu();
this.add(_treeview);
}
private void init_columns()
{
/*
var playing_column = new Gtk.TreeViewColumn.with_attributes(
new Gtk.CellRendererToggle(), "active", PlaySourceModel.Column.PLAYING);
playing_column.set_fixed_width(30);
_treeview.append_column(playing_column);
*/
_treeview.insert_column_with_attributes(0, " ",
new Gtk.CellRendererToggle(), "active", PlaySourceModel.Column.PLAYING);
_treeview.insert_column_with_data_func(1, "Track", new Gtk.CellRendererText(),
(column, cell, model, iter) => {
Value value;
model.get_value(iter, PlaySourceModel.Column.TRACK_NUMBER, out value);
cell.set("text", value.get_int().to_string());
}, null);
_treeview.insert_column_with_attributes(2, "Artist",
new Gtk.CellRendererText(), "text", PlaySourceModel.Column.ARTIST);
_treeview.insert_column_with_attributes(3, "Title",
new Gtk.CellRendererText(), "text", PlaySourceModel.Column.TITLE);
_treeview.insert_column_with_attributes(4, "Album",
new Gtk.CellRendererText(), "text", PlaySourceModel.Column.ALBUM);
_treeview.insert_column_with_attributes(5, "Year",
new Gtk.CellRendererText(), "text", PlaySourceModel.Column.YEAR);
_treeview.insert_column_with_attributes(6, "Rating",
new Gtk.CellRendererText(), "text", PlaySourceModel.Column.RATING);
foreach(Gtk.TreeViewColumn col in (List<Gtk.TreeViewColumn>)_treeview.get_columns()) {
col.set_reorderable(true);
col.set_resizable(true);
col.set_fixed_width(60);
}
}
private void init_context_menu()
{
_context_menu = new ContextMenu(this);
_context_menu.add_item("play", null, "gtk-media-play");
_context_menu.add_item("play-multiple", "_Play in New Playlist", "gtk-media-play");
_context_menu.add_item("add-to-playlist", "Add to New Playlist");
_context_menu.add_item("delete", null, "gtk-delete");
_context_menu.add_separator();
_context_menu.add_item("rating-1", "Rating: 0.5");
_context_menu.add_item("rating-2", "Rating: 1");
_context_menu.add_item("rating-3", "Rating: 1.5");
_context_menu.add_item("rating-4", "Rating: 2");
_context_menu.add_item("rating-5", "Rating: 2.5");
_context_menu.add_item("rating-6", "Rating: 3");
_context_menu.add_item("rating-7", "Rating: 3.5");
_context_menu.add_item("rating-8", "Rating: 4");
_context_menu.add_item("rating-9", "Rating: 4.5");
_context_menu.add_item("rating-10", "Rating: 5");
_context_menu.add_separator();
_context_menu.add_item("open-album", "Open _Album");
_context_menu.add_item("open-album-in-new-tab", "Open Album in New Tab");
_context_menu.add_separator();
_context_menu.add_item("open-artist", "Open Ar_tist");
_context_menu.add_item("open-artist-in-new-tab", "Open Artist in New Tab");
_context_menu.add_separator();
_context_menu.add_item("select-all", null, "gtk-select-all");
_context_menu.add_item("select-album", "Select Album");
_context_menu.add_item("select-artist", "Select Artist");
_treeview.button_press_event += (treeview, event) => {
if (event.button == 3) {
var tree_selection = _treeview.get_selection();
Gtk.TreePath path;
bool on_track = _treeview.get_path_at_pos((int)event.x, (int)event.y, out path, null, null, null);
bool multiple_tracks = false;
if (on_track) {
var mouse_over_index = _treemodel.get_index_from_path(path);
GLib.List<Gtk.TreePath> selected_rows = tree_selection.get_selected_rows(null);
weak GLib.List<Gtk.TreePath> row = selected_rows.first();
bool on_selected_track = false;
while (row != null) {
int this_index = _treemodel.get_index_from_path(row.data);
if (this_index == mouse_over_index)
on_selected_track = true;
row = row.next;
}
if (!on_selected_track) {
tree_selection.unselect_all();
tree_selection.select_path(_treemodel.get_path_from_index(mouse_over_index));
}
}
else
tree_selection.unselect_all();
_context_menu.popup(event.button, event.time);
return true;
}
return false;
};
}
public int[] get_selected_indexes()
{
GLib.List<Gtk.TreePath> selected_rows =
_treeview.get_selection().get_selected_rows(null);
var row_indexes = new int[selected_rows.length()];
int last_index = -1;
for (int i = 0; i < row_indexes.length; i++) {
int smallest_index = int.MAX;
weak GLib.List<Gtk.TreePath> row = selected_rows.first();
while (row != null) {
int this_index = _treemodel.get_index_from_path(row.data);
if (this_index < smallest_index && this_index > last_index)
smallest_index = this_index;
row = row.next;
}
/*foreach(Gtk.TreePath path in selected_rows) {
int this_index = _treemodel.get_index_from_path(path);
if (this_index < smallest_index && this_index > last_index)
smallest_index = this_index;
}*/
row_indexes[i] = smallest_index;
last_index = smallest_index;
}
return row_indexes;
}
public void select_all()
{
_treeview.get_selection().select_all();
}
// ----------------------------------------[Drag n Drop]----------------------------------------
private int _dnd_source_x;
private int _dnd_source_y;
private IPlaySource* _dnd_source;
private int _dnd_source_index;
private string[] _dnd_uris;
private void init_dnd()
{
var targets = new Gtk.TargetEntry[1];
targets[0].target = "ECHO_PLAYLIST_ITEM";
targets[0].flags = Gtk.TargetFlags.SAME_APP;
targets[0].info = 1;
Gtk.drag_source_set(_treeview, Gdk.ModifierType.MODIFIER_MASK, targets, Gdk.DragAction.MOVE);
Gtk.drag_source_set_icon_name(_treeview, "audio-x-generic");
_treeview.drag_data_get += on_drag_data_get;
_treeview.button_press_event += (treeview, event) => {
_dnd_source_x = (int)event.x;
_dnd_source_y = (int)event.y;
return false;
};
if (_mod_source != null) {
Gtk.drag_dest_set(_treeview, 0, targets, Gdk.DragAction.MOVE | Gdk.DragAction.COPY);
Gtk.drag_dest_add_uri_targets(_treeview);
_treeview.drag_data_received += on_drag_data_received;
_treeview.drag_motion += on_drag_motion;
_treeview.drag_drop += on_drag_drop;
_treeview.drag_leave += (treeview, drag_context, time) => {
treeview.set_drag_dest_row(null, Gtk.TreeViewDropPosition.BEFORE);
};
}
}
private void on_drag_data_get(Gtk.TreeView treeview, Gdk.DragContext drag_context,
Gtk.SelectionData selection_data, uint info, uint time)
{
assert(selection_data.target.name() == "ECHO_PLAYLIST_ITEM");
assert(info == 1);
Gtk.TreePath path;
if (_treeview.get_path_at_pos(
_dnd_source_x, _dnd_source_y, out path, null, null, null)) {
int index = _treemodel.get_index_from_path(path);
var data = new uchar[(int)(sizeof(void*) + sizeof(int))];
Memory.copy(data, &_source, sizeof(void*));
Memory.copy((void*)data + sizeof(void*), &index, sizeof(int));
selection_data.set(selection_data.target, 0, data);
}
else {
var data = new uchar[(int)(sizeof(void*) + sizeof(int))];
Memory.set(data, 0, sizeof(void*) + sizeof(int));
selection_data.set(selection_data.target, 0, data);
}
}
private void on_drag_data_received(Gtk.TreeView treeview, Gdk.DragContext drag_context,
int x, int y, Gtk.SelectionData selection_data, uint info, uint time)
{
if (info == 0) {
_dnd_uris = selection_data.get_uris();
_dnd_source = null;
_dnd_source_index = -1;
}
else {
assert(info == 1);
assert(selection_data.target.name() == "ECHO_PLAYLIST_ITEM");
_dnd_uris = null;
Memory.copy(&_dnd_source, (void*)selection_data.data, sizeof(void*));
Memory.copy(&_dnd_source_index, (void*)selection_data.data + sizeof(void*), sizeof(int));
}
Signal.stop_emission_by_name(treeview, "drag-data-received");
}
private bool on_drag_motion(Gtk.TreeView treeview, Gdk.DragContext drag_context,
int x, int y, uint time)
{
var target_list = Gtk.drag_dest_get_target_list(treeview);
var target = Gtk.drag_dest_find_target(treeview, drag_context, target_list);
if (target == (Gdk.Atom)0)
return false;
Gtk.TreePath path;
Gtk.TreeViewDropPosition pos;
if (treeview.get_dest_row_at_pos(x, y, out path, out pos)) {
if (pos == Gtk.TreeViewDropPosition.INTO_OR_BEFORE)
pos = Gtk.TreeViewDropPosition.BEFORE;
if (pos == Gtk.TreeViewDropPosition.INTO_OR_AFTER)
pos = Gtk.TreeViewDropPosition.AFTER;
treeview.set_drag_dest_row(path, pos);
}
else {
int binx, biny;
treeview.convert_widget_to_bin_window_coords(x, y, out binx, out biny);
if (biny < 0) {
treeview.set_drag_dest_row(null, 0);
return false;
}
if (_source.get_num_tracks() > 0)
treeview.set_drag_dest_row(
_treemodel.get_path_from_index(_source.get_num_tracks() - 1),
Gtk.TreeViewDropPosition.AFTER);
else
treeview.set_drag_dest_row(
_treemodel.get_path_from_index(0, false),
Gtk.TreeViewDropPosition.BEFORE);
}
Gtk.drag_get_data(treeview, drag_context, target, time);
if (_dnd_source == null && _dnd_uris == null) {
treeview.set_drag_dest_row(null, 0);
return false;
}
if (_dnd_source == _source)
Gdk.drag_status(drag_context, Gdk.DragAction.MOVE, time);
else
Gdk.drag_status(drag_context, Gdk.DragAction.COPY, time);
return true;
}
private int _track_insertion_index;
private bool on_drag_drop(Gtk.TreeView treeview, Gdk.DragContext drag_context,
int x, int y, uint time)
{
var target_list = Gtk.drag_dest_get_target_list(treeview);
var target = Gtk.drag_dest_find_target(treeview, drag_context, target_list);
if (target == (Gdk.Atom)0) {
Gtk.drag_finish(drag_context, false, false, time);
return false;
}
Gtk.drag_get_data(treeview, drag_context, target, time);
assert(_dnd_source != null || _dnd_uris != null);
assert(_dnd_source == null || _dnd_uris == null);
Gtk.TreePath path;
Gtk.TreeViewDropPosition pos;
int index;
if (treeview.get_dest_row_at_pos(x, y, out path, out pos)) {
index = _treemodel.get_index_from_path(path);
if (pos == Gtk.TreeViewDropPosition.INTO_OR_AFTER ||
pos == Gtk.TreeViewDropPosition.AFTER)
index++;
}
else {
index = _source.get_num_tracks();
}
if (_dnd_source != null) {
if (_dnd_source == _source)
_mod_source.move_track(_dnd_source_index, index);
else {
_mod_source.insert_track(index, _dnd_source->get_track(_dnd_source_index));
}
}
if (_dnd_uris != null) {
_track_insertion_index = index;
URIHandler.handle_uris(_dnd_uris, (track) => {
_mod_source.insert_track(_track_insertion_index++, track);
});
}
Gtk.drag_finish(drag_context, true, false, time);
return true;
}
}