2 * Copyright 2006 Timo Hirvonen
8 #include "track_info.h"
12 #include "mergesort.h"
15 pthread_mutex_t editable_mutex
= CMUS_MUTEX_INITIALIZER
;
17 static const struct searchable_ops simple_search_ops
= {
18 .get_prev
= simple_track_get_prev
,
19 .get_next
= simple_track_get_next
,
20 .get_current
= simple_track_search_get_current
,
21 .matches
= simple_track_search_matches
24 static struct simple_track
*get_selected(struct editable
*e
)
28 if (window_get_sel(e
->win
, &sel
))
29 return iter_to_simple_track(&sel
);
33 void editable_init(struct editable
*e
, void (*free_track
)(struct list_head
*item
))
41 e
->sort_keys
= xnew(const char *, 1);
42 e
->sort_keys
[0] = NULL
;
44 e
->free_track
= free_track
;
46 e
->win
= window_new(simple_track_get_prev
, simple_track_get_next
);
47 window_set_contents(e
->win
, &e
->head
);
49 iter
.data0
= &e
->head
;
52 e
->searchable
= searchable_new(e
->win
, &iter
, &simple_search_ops
);
55 void editable_add(struct editable
*e
, struct simple_track
*track
)
57 sorted_list_add_track(&e
->head
, track
, e
->sort_keys
);
59 if (track
->info
->duration
!= -1)
60 e
->total_time
+= track
->info
->duration
;
61 window_changed(e
->win
);
64 void editable_remove_track(struct editable
*e
, struct simple_track
*track
)
66 struct track_info
*ti
= track
->info
;
69 editable_track_to_iter(e
, track
, &iter
);
70 window_row_vanishes(e
->win
, &iter
);
73 e
->nr_marked
-= track
->marked
;
74 if (ti
->duration
!= -1)
75 e
->total_time
-= ti
->duration
;
77 list_del(&track
->node
);
79 e
->free_track(&track
->node
);
82 void editable_remove_sel(struct editable
*e
)
84 struct simple_track
*t
;
87 /* treat marked tracks as selected */
88 struct list_head
*next
, *item
= e
->head
.next
;
90 while (item
!= &e
->head
) {
92 t
= to_simple_track(item
);
94 editable_remove_track(e
, t
);
100 editable_remove_track(e
, t
);
104 static const char **sort_keys
;
106 static int list_cmp(const struct list_head
*a_head
, const struct list_head
*b_head
)
108 return simple_track_cmp(a_head
, b_head
, sort_keys
);
111 void editable_sort(struct editable
*e
)
113 sort_keys
= e
->sort_keys
;
114 list_mergesort(&e
->head
, list_cmp
);
115 window_changed(e
->win
);
116 window_goto_top(e
->win
);
119 static void keys_to_str(const char **keys
, char *buf
)
123 for (i
= 0; keys
[i
]; i
++) {
124 const char *key
= keys
[i
];
125 int len
= strlen(key
);
127 if (sizeof(buf
) - pos
- len
- 2 < 0)
130 memcpy(buf
+ pos
, key
, len
);
139 void editable_set_sort_keys(struct editable
*e
, const char **keys
)
144 keys_to_str(keys
, e
->sort_str
);
147 void editable_toggle_mark(struct editable
*e
)
149 struct simple_track
*t
;
153 e
->nr_marked
-= t
->marked
;
155 e
->nr_marked
+= t
->marked
;
157 window_down(e
->win
, 1);
161 static void move_item(struct editable
*e
, struct list_head
*head
, struct list_head
*item
)
163 struct simple_track
*t
= to_simple_track(item
);
166 editable_track_to_iter(e
, t
, &iter
);
167 window_row_vanishes(e
->win
, &iter
);
170 list_add(item
, head
);
173 static void move_sel(struct editable
*e
, struct list_head
*after
)
175 struct simple_track
*t
;
176 struct list_head
*item
, *next
;
183 while (item
!= &e
->head
) {
184 t
= to_simple_track(item
);
187 move_item(e
, &tmp_head
, item
);
191 /* collect the selected track */
193 move_item(e
, &tmp_head
, &t
->node
);
196 /* put them back to the list after @after */
197 item
= tmp_head
.next
;
198 while (item
!= &tmp_head
) {
200 list_add(item
, after
);
204 /* select top-most of the moved tracks */
205 editable_track_to_iter(e
, to_simple_track(after
->next
), &iter
);
206 window_set_sel(e
->win
, &iter
);
207 window_changed(e
->win
);
210 static struct list_head
*find_insert_after_point(struct editable
*e
, struct list_head
*item
)
212 if (e
->nr_marked
== 0) {
213 /* move the selected track down one row */
217 /* move marked after the selected
219 * if the selected track itself is marked we find the first unmarked
220 * track (or head) before the selected one
222 while (item
!= &e
->head
) {
223 struct simple_track
*t
= to_simple_track(item
);
232 static struct list_head
*find_insert_before_point(struct editable
*e
, struct list_head
*item
)
235 if (e
->nr_marked
== 0) {
236 /* move the selected track up one row */
240 /* move marked before the selected
242 * if the selected track itself is marked we find the first unmarked
243 * track (or head) before the selected one
245 while (item
!= &e
->head
) {
246 struct simple_track
*t
= to_simple_track(item
);
255 void editable_move_after(struct editable
*e
)
257 struct simple_track
*sel
;
259 if (e
->nr_tracks
<= 1)
262 if (e
->sort_keys
[0] == NULL
&& (sel
= get_selected(e
)))
263 move_sel(e
, find_insert_after_point(e
, &sel
->node
));
266 void editable_move_before(struct editable
*e
)
268 struct simple_track
*sel
;
270 if (e
->nr_tracks
<= 1)
273 if (e
->sort_keys
[0] == NULL
&& (sel
= get_selected(e
)))
274 move_sel(e
, find_insert_before_point(e
, &sel
->node
));
277 void editable_clear(struct editable
*e
)
279 struct list_head
*item
, *next
;
282 while (item
!= &e
->head
) {
284 editable_remove_track(e
, to_simple_track(item
));
289 void editable_mark(struct editable
*e
, const char *filter
)
291 struct expr
*expr
= NULL
;
292 struct simple_track
*t
;
295 expr
= parse_filter(filter
);
300 list_for_each_entry(t
, &e
->head
, node
) {
301 e
->nr_marked
-= t
->marked
;
303 if (expr
== NULL
|| expr_eval(expr
, t
->info
)) {
311 void editable_unmark(struct editable
*e
)
313 struct simple_track
*t
;
315 list_for_each_entry(t
, &e
->head
, node
) {
316 e
->nr_marked
-= t
->marked
;
322 void editable_invert_marks(struct editable
*e
)
324 struct simple_track
*t
;
326 list_for_each_entry(t
, &e
->head
, node
) {
327 e
->nr_marked
-= t
->marked
;
329 e
->nr_marked
+= t
->marked
;
334 int __editable_for_each_sel(struct editable
*e
, int (*cb
)(void *data
, struct track_info
*ti
),
335 void *data
, int reverse
)
340 /* treat marked tracks as selected */
341 rc
= simple_list_for_each_marked(&e
->head
, cb
, data
, reverse
);
343 struct simple_track
*t
= get_selected(e
);
346 rc
= cb(data
, t
->info
);
351 int editable_for_each_sel(struct editable
*e
, int (*cb
)(void *data
, struct track_info
*ti
),
352 void *data
, int reverse
)
356 rc
= __editable_for_each_sel(e
, cb
, data
, reverse
);
357 if (e
->nr_marked
== 0)
358 window_down(e
->win
, 1);