Lines 17-22
Link Here
|
17 |
* along with this program; if not, write to the Free Software |
17 |
* along with this program; if not, write to the Free Software |
18 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
18 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 |
*/ |
19 |
*/ |
|
|
20 |
#include <assert.h> |
20 |
#include "xmms.h" |
21 |
#include "xmms.h" |
21 |
#include "libxmms/dirbrowser.h" |
22 |
#include "libxmms/dirbrowser.h" |
22 |
#include "libxmms/util.h" |
23 |
#include "libxmms/util.h" |
Lines 24-30
Link Here
|
24 |
GtkWidget *playlistwin; |
25 |
GtkWidget *playlistwin; |
25 |
static GtkWidget *playlistwin_url_window = NULL; |
26 |
static GtkWidget *playlistwin_url_window = NULL; |
26 |
static GtkItemFactory *playlistwin_sort_menu, *playlistwin_sub_menu; |
27 |
static GtkItemFactory *playlistwin_sort_menu, *playlistwin_sub_menu; |
27 |
static GtkItemFactory *playlistwin_popup_menu, *playlistwin_save_menu; |
28 |
static GtkItemFactory *playlistwin_popup_menu, *playlistwin_save_menu, *playlistwin_dtd_menu; |
28 |
|
29 |
|
29 |
static GdkPixmap *playlistwin_bg; |
30 |
static GdkPixmap *playlistwin_bg; |
30 |
static GdkBitmap *playlistwin_mask; |
31 |
static GdkBitmap *playlistwin_mask; |
Lines 67-79
Link Here
|
67 |
SEL_INV, SEL_ZERO, SEL_ALL, |
68 |
SEL_INV, SEL_ZERO, SEL_ALL, |
68 |
MISC_SORT, MISC_FILEINFO, MISC_MISCOPTS, |
69 |
MISC_SORT, MISC_FILEINFO, MISC_MISCOPTS, |
69 |
PLIST_NEW, PLIST_SAVE, PLIST_LOAD, |
70 |
PLIST_NEW, PLIST_SAVE, PLIST_LOAD, |
70 |
SEL_LOOKUP, |
71 |
SEL_LOOKUP, DTD_GOODSONG, DTD_BADSONG, |
|
|
72 |
DTD_DISSOCIATE |
71 |
}; |
73 |
}; |
72 |
|
74 |
|
73 |
void playlistwin_sort_menu_callback(gpointer cb_data, guint action, GtkWidget * w); |
75 |
void playlistwin_sort_menu_callback(gpointer cb_data, guint action, GtkWidget * w); |
74 |
void playlistwin_sub_menu_callback(gpointer cb_data, guint action, GtkWidget * w); |
76 |
void playlistwin_sub_menu_callback(gpointer cb_data, guint action, GtkWidget * w); |
75 |
void playlistwin_save_type_cb(gpointer cb_data, guint action, GtkWidget * w); |
77 |
void playlistwin_save_type_cb(gpointer cb_data, guint action, GtkWidget * w); |
76 |
void playlistwin_set_hints(void); |
78 |
void playlistwin_set_hints(void); |
|
|
79 |
void playlistwin_dissociate_callback(GtkMenuItem *menuitem, gpointer ignored); |
77 |
|
80 |
|
78 |
enum |
81 |
enum |
79 |
{ |
82 |
{ |
Lines 150-156
Link Here
|
150 |
GtkItemFactoryEntry playlistwin_popup_menu_entries[] = |
153 |
GtkItemFactoryEntry playlistwin_popup_menu_entries[] = |
151 |
{ |
154 |
{ |
152 |
{N_("/View File Info"), NULL, playlistwin_popup_menu_callback, MISC_FILEINFO, "<Item>"}, |
155 |
{N_("/View File Info"), NULL, playlistwin_popup_menu_callback, MISC_FILEINFO, "<Item>"}, |
|
|
156 |
|
153 |
{N_("/-"), NULL, NULL, 0, "<Separator>"}, |
157 |
{N_("/-"), NULL, NULL, 0, "<Separator>"}, |
|
|
158 |
|
159 |
{N_("/Dynamic Taste Detection"), NULL, NULL, 0, "<Item>"}, |
160 |
|
154 |
{N_("/Add"), NULL, NULL, 0, "<Branch>"}, |
161 |
{N_("/Add"), NULL, NULL, 0, "<Branch>"}, |
155 |
{N_("/Add/File"), NULL, playlistwin_popup_menu_callback, ADD_FILE, "<Item>"}, |
162 |
{N_("/Add/File"), NULL, playlistwin_popup_menu_callback, ADD_FILE, "<Item>"}, |
156 |
{N_("/Add/Directory"), NULL, playlistwin_popup_menu_callback, ADD_DIR, "<Item>"}, |
163 |
{N_("/Add/Directory"), NULL, playlistwin_popup_menu_callback, ADD_DIR, "<Item>"}, |
Lines 181-186
Link Here
|
181 |
sizeof(playlistwin_popup_menu_entries) / |
188 |
sizeof(playlistwin_popup_menu_entries) / |
182 |
sizeof(playlistwin_popup_menu_entries[0]); |
189 |
sizeof(playlistwin_popup_menu_entries[0]); |
183 |
|
190 |
|
|
|
191 |
GtkItemFactoryEntry playlistwin_dtd_menu_entries[] = |
192 |
{ |
193 |
{N_("/I Like this Song"), |
194 |
NULL, playlistwin_popup_menu_callback, DTD_GOODSONG, |
195 |
"<RadioItem>"}, |
196 |
{N_("/I Don't Like this Song"), |
197 |
NULL, playlistwin_popup_menu_callback, DTD_BADSONG, |
198 |
/* <RadioItem> */ "/I Like this Song"}, |
199 |
{N_("/Dissociate From"), NULL, NULL, 0, "<Item>"} |
200 |
}; |
201 |
|
202 |
static const int playlistwin_dtd_menu_entries_num = |
203 |
sizeof(playlistwin_dtd_menu_entries) / |
204 |
sizeof(playlistwin_dtd_menu_entries[0]); |
205 |
|
184 |
void playlistwin_draw_frame(void); |
206 |
void playlistwin_draw_frame(void); |
185 |
|
207 |
|
186 |
static void playlistwin_update_info(void) |
208 |
static void playlistwin_update_info(void) |
Lines 1029-1034
Link Here
|
1029 |
case PLIST_LOAD: |
1051 |
case PLIST_LOAD: |
1030 |
playlistwin_show_load_filesel(); |
1052 |
playlistwin_show_load_filesel(); |
1031 |
break; |
1053 |
break; |
|
|
1054 |
|
1055 |
/* DTD button */ |
1056 |
case DTD_GOODSONG: { |
1057 |
gint score; |
1058 |
gint selected_playlist_pos = playlist_get_single_selection(); |
1059 |
|
1060 |
assert(selected_playlist_pos > -1); |
1061 |
score = playlist_get_score(selected_playlist_pos); |
1062 |
if (score < 0) |
1063 |
{ |
1064 |
playlist_set_score(selected_playlist_pos, 0); |
1065 |
} |
1066 |
|
1067 |
break; |
1068 |
} |
1069 |
|
1070 |
case DTD_BADSONG: { |
1071 |
gint score; |
1072 |
gint selected_playlist_pos = playlist_get_single_selection(); |
1073 |
|
1074 |
assert(selected_playlist_pos > -1); |
1075 |
score = playlist_get_score(selected_playlist_pos); |
1076 |
if (score >= 0) |
1077 |
{ |
1078 |
playlist_set_score(selected_playlist_pos, -1); |
1079 |
} |
1080 |
|
1081 |
break; |
1082 |
} |
1032 |
} |
1083 |
} |
1033 |
} |
1084 |
} |
1034 |
|
1085 |
|
Lines 1052-1057
Link Here
|
1052 |
inside_widget(x, y, playlistwin_sscroll_down)); |
1103 |
inside_widget(x, y, playlistwin_sscroll_down)); |
1053 |
} |
1104 |
} |
1054 |
|
1105 |
|
|
|
1106 |
gchar *playlistwin_fileName2songName(const gchar *fileName) |
1107 |
{ |
1108 |
const gchar *afterLastSlash, *beforeLastDot, *c; |
1109 |
gchar *returnMe; |
1110 |
gint i; |
1111 |
const gchar *loadedTitle = |
1112 |
playlist_filename2songtitle(fileName); |
1113 |
|
1114 |
if (loadedTitle != NULL) |
1115 |
{ |
1116 |
return g_strdup(loadedTitle); |
1117 |
} |
1118 |
|
1119 |
// Ditch the last slash and everything before it, as well as |
1120 |
// the last dot and everything after it before returning it. |
1121 |
afterLastSlash = strrchr(fileName, '/'); |
1122 |
if (afterLastSlash != NULL) |
1123 |
{ |
1124 |
afterLastSlash++; |
1125 |
} |
1126 |
else |
1127 |
{ |
1128 |
afterLastSlash = fileName; |
1129 |
} |
1130 |
|
1131 |
beforeLastDot = strrchr(fileName, '.'); |
1132 |
if ((beforeLastDot != NULL) && (beforeLastDot > afterLastSlash)) |
1133 |
{ |
1134 |
beforeLastDot--; |
1135 |
} |
1136 |
else |
1137 |
{ |
1138 |
beforeLastDot = fileName + strlen(fileName) - 1; |
1139 |
} |
1140 |
|
1141 |
if ((afterLastSlash >= beforeLastDot) || |
1142 |
(beforeLastDot <= fileName) || |
1143 |
((afterLastSlash - fileName) >= strlen(fileName))) |
1144 |
{ |
1145 |
return g_strdup(fileName); |
1146 |
} |
1147 |
|
1148 |
// Copy from after last slash to before last dot |
1149 |
returnMe = g_new(gchar, (beforeLastDot - afterLastSlash) + 1); |
1150 |
i = 0; |
1151 |
for (c = afterLastSlash; c <= beforeLastDot; c++) |
1152 |
{ |
1153 |
returnMe[i++] = *c; |
1154 |
} |
1155 |
returnMe[i] = '\0'; |
1156 |
|
1157 |
return returnMe; |
1158 |
} |
1159 |
|
1160 |
void playlistwin_remove_dissociation_menu(GtkMenuItem *attachPoint) |
1161 |
{ |
1162 |
// Nuke any previous dissociations menu |
1163 |
|
1164 |
// FIXME: I have absolutely no clue to how GTK+ refcounting |
1165 |
// works. This implementation may or may not leak memory. |
1166 |
// Candidates for memory leaks are the user_data fields of the |
1167 |
// labels (they should be freed). |
1168 |
// /Johan Walles - jan 05 / 2002 |
1169 |
gtk_menu_item_remove_submenu(attachPoint); |
1170 |
} |
1171 |
|
1172 |
void playlistwin_setup_dissociation_menu(GtkMenuItem *attachPoint, |
1173 |
gint selected_playlist_pos) |
1174 |
{ |
1175 |
const GList *recommendations = NULL; |
1176 |
const gchar *filename = playlist_get_filename(selected_playlist_pos); |
1177 |
|
1178 |
// Ditch the previous dissociations menu (if any) |
1179 |
playlistwin_remove_dissociation_menu(attachPoint); |
1180 |
|
1181 |
recommendations = |
1182 |
dtd_get_recommendations(filename); |
1183 |
|
1184 |
if (recommendations != NULL) |
1185 |
{ |
1186 |
// Create a new menu |
1187 |
GtkWidget *dissociateMenu = gtk_menu_new(); |
1188 |
const GList *iterator; |
1189 |
|
1190 |
// Associate it with the selected song |
1191 |
gtk_object_set_user_data(GTK_OBJECT(dissociateMenu), g_strdup(filename)); |
1192 |
|
1193 |
// For all recommendations... |
1194 |
for (iterator = recommendations; |
1195 |
iterator != NULL; |
1196 |
iterator = g_list_next(iterator)) |
1197 |
{ |
1198 |
const gchar *filename = ((DtdNextSong *)(iterator->data))->filename; |
1199 |
gchar *songName = playlistwin_fileName2songName(filename); |
1200 |
GtkWidget *newMenuItem; |
1201 |
|
1202 |
// ... create a new menu entry... |
1203 |
newMenuItem = gtk_menu_item_new_with_label(songName); |
1204 |
g_free(songName); |
1205 |
|
1206 |
// ... with its user_data set to point |
1207 |
// to the associated file name... |
1208 |
gtk_object_set_user_data(GTK_OBJECT(newMenuItem), g_strdup(filename)); |
1209 |
|
1210 |
// ... tell it what to do on receiving a click... |
1211 |
gtk_signal_connect(GTK_OBJECT(newMenuItem), |
1212 |
"activate", |
1213 |
GTK_SIGNAL_FUNC(playlistwin_dissociate_callback), |
1214 |
NULL); |
1215 |
|
1216 |
// ... and add it to the new menu. |
1217 |
gtk_menu_append(GTK_MENU(dissociateMenu), newMenuItem); |
1218 |
} |
1219 |
|
1220 |
// Enable our new dissociations menu |
1221 |
gtk_widget_show_all(dissociateMenu); |
1222 |
gtk_menu_item_set_submenu(attachPoint, dissociateMenu); |
1223 |
gtk_widget_set_sensitive(GTK_WIDGET(attachPoint), 1); |
1224 |
} |
1225 |
else |
1226 |
{ |
1227 |
// ... or disable the dissociation menu heading |
1228 |
// if there is nothing to dissociate from. |
1229 |
gtk_widget_set_sensitive(GTK_WIDGET(attachPoint), 0); |
1230 |
} |
1231 |
} |
1232 |
|
1055 |
#define REGION_L(x1,x2,y1,y2) \ |
1233 |
#define REGION_L(x1,x2,y1,y2) \ |
1056 |
(event->x >= (x1) && event->x < (x2) && \ |
1234 |
(event->x >= (x1) && event->x < (x2) && \ |
1057 |
event->y >= cfg.playlist_height - (y1) && \ |
1235 |
event->y >= cfg.playlist_height - (y1) && \ |
Lines 1226-1243
Link Here
|
1226 |
else if (event->button == 3 && |
1404 |
else if (event->button == 3 && |
1227 |
inside_widget(event->x, event->y, playlistwin_list)) |
1405 |
inside_widget(event->x, event->y, playlistwin_list)) |
1228 |
{ |
1406 |
{ |
1229 |
int pos, sensitive; |
1407 |
// FIXME: This block is much too long, put it in its |
|
|
1408 |
// own function |
1409 |
|
1410 |
gint clicked_playlist_pos, selected_playlist_pos; |
1411 |
gboolean sensitive; |
1412 |
|
1230 |
GtkWidget *w; |
1413 |
GtkWidget *w; |
1231 |
pos = playlist_list_get_playlist_position(playlistwin_list, |
1414 |
|
1232 |
event->x, event->y); |
1415 |
clicked_playlist_pos = |
1233 |
sensitive = pos != -1; |
1416 |
playlist_list_get_playlist_position(playlistwin_list, |
|
|
1417 |
event->x, event->y); |
1418 |
|
1419 |
// Unless the clicked song is part of a (multiple) |
1420 |
// selection... |
1421 |
if (!playlist_is_selected(clicked_playlist_pos)) |
1422 |
{ |
1423 |
// ... select just the current song before |
1424 |
// displaying the menu |
1425 |
playlist_select_all(0); |
1426 |
playlist_select_range(clicked_playlist_pos, clicked_playlist_pos, 1); |
1427 |
playlistwin_update_list(); |
1428 |
} |
1429 |
|
1430 |
selected_playlist_pos = playlist_get_single_selection(); |
1431 |
sensitive = (selected_playlist_pos != -1); |
1432 |
|
1433 |
// Disable "View File Info" if not exactly one song is selected |
1234 |
w = gtk_item_factory_get_widget(playlistwin_popup_menu, |
1434 |
w = gtk_item_factory_get_widget(playlistwin_popup_menu, |
1235 |
"/View File Info"); |
1435 |
"/View File Info"); |
1236 |
gtk_widget_set_sensitive(w, sensitive); |
1436 |
gtk_widget_set_sensitive(w, sensitive); |
|
|
1437 |
|
1438 |
// Disable the DTD menu hierarchy if not exactly one |
1439 |
// song is selected |
1440 |
// FIXME: or if it's disabled in the prefs |
1441 |
w = gtk_item_factory_get_widget(playlistwin_popup_menu, |
1442 |
"/Dynamic Taste Detection"); |
1443 |
gtk_widget_set_sensitive(w, sensitive); |
1444 |
|
1445 |
if (sensitive) |
1446 |
{ |
1447 |
GtkWidget *playlistwin_dtd_menu_widget = |
1448 |
gtk_item_factory_get_widget(playlistwin_dtd_menu, "<Main>"); |
1449 |
|
1450 |
gtk_widget_show_all(playlistwin_dtd_menu_widget); |
1451 |
gtk_menu_item_set_submenu(GTK_MENU_ITEM(w), playlistwin_dtd_menu_widget); |
1452 |
} |
1453 |
else |
1454 |
{ |
1455 |
gtk_menu_item_remove_submenu(GTK_MENU_ITEM(w)); |
1456 |
gtk_widget_hide_all(gtk_item_factory_get_widget(playlistwin_dtd_menu, "<Main>")); |
1457 |
} |
1458 |
|
1459 |
if (selected_playlist_pos != -1) |
1460 |
{ |
1461 |
// Enable either "/I Like this Song" (if the |
1462 |
// song scores >= 0) or "Bad Song" (if the |
1463 |
// song scores < 0). |
1464 |
gint score = dtd_get_score(playlist_get_filename(selected_playlist_pos)); |
1465 |
|
1466 |
w = gtk_item_factory_get_widget(playlistwin_dtd_menu, |
1467 |
"/I Like this Song"); |
1468 |
if (score >= 0) |
1469 |
{ |
1470 |
gtk_check_menu_item_set_state(GTK_CHECK_MENU_ITEM(w), 1); |
1471 |
} |
1472 |
gtk_widget_set_sensitive(w, 1); |
1473 |
w = gtk_item_factory_get_widget(playlistwin_dtd_menu, |
1474 |
"/I Don't Like this Song"); |
1475 |
if (score < 0) |
1476 |
{ |
1477 |
gtk_check_menu_item_set_state(GTK_CHECK_MENU_ITEM(w), 1); |
1478 |
} |
1479 |
gtk_widget_set_sensitive(w, 1); |
1480 |
} |
1481 |
else |
1482 |
{ |
1483 |
// We don't do ratings of multiple songs at once |
1484 |
w = gtk_item_factory_get_widget(playlistwin_dtd_menu, |
1485 |
"/I Like this Song"); |
1486 |
gtk_widget_set_sensitive(w, 0); |
1487 |
gtk_check_menu_item_set_state(GTK_CHECK_MENU_ITEM(w), 0); |
1488 |
w = gtk_item_factory_get_widget(playlistwin_dtd_menu, |
1489 |
"/I Don't Like this Song"); |
1490 |
gtk_widget_set_sensitive(w, 0); |
1491 |
gtk_check_menu_item_set_state(GTK_CHECK_MENU_ITEM(w), 0); |
1492 |
} |
1237 |
|
1493 |
|
|
|
1494 |
// Create the dissociation menu |
1495 |
w = gtk_item_factory_get_widget(playlistwin_dtd_menu, |
1496 |
"/Dissociate From"); |
1497 |
playlistwin_setup_dissociation_menu(GTK_MENU_ITEM(w), selected_playlist_pos); |
1498 |
|
1238 |
playlistwin_set_sensitive_sortmenu(); |
1499 |
playlistwin_set_sensitive_sortmenu(); |
1239 |
util_item_factory_popup_with_data(playlistwin_popup_menu, |
1500 |
util_item_factory_popup_with_data(playlistwin_popup_menu, |
1240 |
GINT_TO_POINTER(pos), NULL, |
1501 |
GINT_TO_POINTER(selected_playlist_pos), NULL, |
1241 |
event->x_root, |
1502 |
event->x_root, |
1242 |
event->y_root + 5, |
1503 |
event->y_root + 5, |
1243 |
3, event->time); |
1504 |
3, event->time); |
Lines 1944-1949
Link Here
|
1944 |
cfg.playlist_height, |
2205 |
cfg.playlist_height, |
1945 |
gdk_rgb_get_visual()->depth); |
2206 |
gdk_rgb_get_visual()->depth); |
1946 |
|
2207 |
|
|
|
2208 |
playlistwin_dtd_menu = gtk_item_factory_new(GTK_TYPE_MENU, "<Main>", NULL); |
2209 |
gtk_item_factory_create_items(GTK_ITEM_FACTORY(playlistwin_dtd_menu), |
2210 |
playlistwin_dtd_menu_entries_num, |
2211 |
playlistwin_dtd_menu_entries, NULL); |
2212 |
|
1947 |
playlistwin_popup_menu = |
2213 |
playlistwin_popup_menu = |
1948 |
gtk_item_factory_new(GTK_TYPE_MENU, "<Main>", NULL); |
2214 |
gtk_item_factory_new(GTK_TYPE_MENU, "<Main>", NULL); |
1949 |
gtk_item_factory_set_translate_func(playlistwin_popup_menu, |
2215 |
gtk_item_factory_set_translate_func(playlistwin_popup_menu, |
Lines 2020-2025
Link Here
|
2020 |
tbutton_set_toggled(mainwin_pl, FALSE); |
2286 |
tbutton_set_toggled(mainwin_pl, FALSE); |
2021 |
} |
2287 |
} |
2022 |
|
2288 |
|
|
|
2289 |
void playlistwin_dissociate_callback(GtkMenuItem *menuitem, |
2290 |
gpointer ignored) |
2291 |
{ |
2292 |
gchar *first, *second; |
2293 |
|
2294 |
// Find out "first" by checking the user data of the menuitem |
2295 |
// that was activated |
2296 |
first = (gchar *)gtk_object_get_user_data(GTK_OBJECT(menuitem)); |
2297 |
|
2298 |
// Find out "second" by checking the user data of the menu |
2299 |
// that is the parent of the menuitem that was activated |
2300 |
second = (gchar *)gtk_object_get_user_data(GTK_OBJECT(GTK_WIDGET(menuitem)->parent)); |
2301 |
|
2302 |
dtd_dissociate(first, second); |
2303 |
} |
2304 |
|
2305 |
|
2023 |
void playlistwin_popup_menu_callback(gpointer cb_data, guint action, GtkWidget * w) |
2306 |
void playlistwin_popup_menu_callback(gpointer cb_data, guint action, GtkWidget * w) |
2024 |
{ |
2307 |
{ |
2025 |
int pos = GPOINTER_TO_INT(gtk_item_factory_popup_data_from_widget(w)); |
2308 |
int pos = GPOINTER_TO_INT(gtk_item_factory_popup_data_from_widget(w)); |
Lines 2032-2037
Link Here
|
2032 |
case SEL_LOOKUP: |
2315 |
case SEL_LOOKUP: |
2033 |
playlist_read_info_selection(); |
2316 |
playlist_read_info_selection(); |
2034 |
break; |
2317 |
break; |
|
|
2318 |
case DTD_DISSOCIATE: |
2319 |
|
2320 |
break; |
2321 |
case DTD_GOODSONG: |
2322 |
case DTD_BADSONG: |
2323 |
// Act only upon the active item |
2324 |
if (GTK_CHECK_MENU_ITEM(w)->active) |
2325 |
{ |
2326 |
playlistwin_popup_handler(action); |
2327 |
} |
2328 |
break; |
2035 |
default: |
2329 |
default: |
2036 |
playlistwin_popup_handler(action); |
2330 |
playlistwin_popup_handler(action); |
2037 |
} |
2331 |
} |