gui: macos: use float for rate
[vlc.git] / src / playlist / content.c
blob43b3800d9f6e8b79d8847485fb3d71bcd221a0d2
1 /*****************************************************************************
2 * playlist/content.c
3 *****************************************************************************
4 * Copyright (C) 2018 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
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 Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include "content.h"
27 #include "control.h"
28 #include "item.h"
29 #include "notify.h"
30 #include "playlist.h"
32 void
33 vlc_playlist_ClearItems(vlc_playlist_t *playlist)
35 vlc_playlist_item_t *item;
36 vlc_vector_foreach(item, &playlist->items)
37 vlc_playlist_item_Release(item);
38 vlc_vector_clear(&playlist->items);
41 static void
42 vlc_playlist_ItemsReset(vlc_playlist_t *playlist)
44 if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM)
45 randomizer_Clear(&playlist->randomizer);
47 struct vlc_playlist_state state;
48 vlc_playlist_state_Save(playlist, &state);
50 playlist->current = -1;
51 playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
52 playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
54 vlc_playlist_Notify(playlist, on_items_reset, playlist->items.data,
55 playlist->items.size);
56 vlc_playlist_state_NotifyChanges(playlist, &state);
59 static void
60 vlc_playlist_ItemsInserted(vlc_playlist_t *playlist, size_t index, size_t count)
62 if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM)
63 randomizer_Add(&playlist->randomizer,
64 &playlist->items.data[index], count);
66 struct vlc_playlist_state state;
67 vlc_playlist_state_Save(playlist, &state);
69 if (playlist->current >= (ssize_t) index)
70 playlist->current += count;
71 playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
72 playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
74 vlc_playlist_item_t **items = &playlist->items.data[index];
75 vlc_playlist_Notify(playlist, on_items_added, index, items, count);
76 vlc_playlist_state_NotifyChanges(playlist, &state);
79 static void
80 vlc_playlist_ItemsMoved(vlc_playlist_t *playlist, size_t index, size_t count,
81 size_t target)
83 struct vlc_playlist_state state;
84 vlc_playlist_state_Save(playlist, &state);
86 if (playlist->current != -1) {
87 size_t current = (size_t) playlist->current;
88 if (index < target)
90 if (current >= index && current < index + count)
91 /* current item belongs to the moved block */
92 playlist->current += target - index;
93 else if (current >= index + count && current < target + count)
94 /* current item was shifted backwards to the moved block */
95 playlist->current -= count;
96 /* else the current item does not move */
98 else
100 if (current >= index && current < index + count)
101 /* current item belongs to the moved block */
102 playlist->current -= index - target;
103 else if (current >= target && current < index)
104 /* current item was shifted forward to the moved block */
105 playlist->current += count;
106 /* else the current item does not move */
110 playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
111 playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
113 vlc_playlist_Notify(playlist, on_items_moved, index, count, target);
114 vlc_playlist_state_NotifyChanges(playlist, &state);
117 static void
118 vlc_playlist_ItemsRemoving(vlc_playlist_t *playlist, size_t index, size_t count)
120 if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM)
121 randomizer_Remove(&playlist->randomizer,
122 &playlist->items.data[index], count);
125 /* return whether the current media has changed */
126 static bool
127 vlc_playlist_ItemsRemoved(vlc_playlist_t *playlist, size_t index, size_t count)
129 struct vlc_playlist_state state;
130 vlc_playlist_state_Save(playlist, &state);
132 bool current_media_changed = false;
133 if (playlist->current != -1) {
134 size_t current = (size_t) playlist->current;
135 if (current >= index && current < index + count) {
136 /* current item has been removed */
137 if (index + count < playlist->items.size) {
138 /* select the first item after the removed block */
139 playlist->current = index;
140 } else {
141 /* no more items */
142 playlist->current = -1;
144 current_media_changed = true;
145 } else if (current >= index + count) {
146 playlist->current -= count;
149 playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
150 playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
152 vlc_playlist_Notify(playlist, on_items_removed, index, count);
153 vlc_playlist_state_NotifyChanges(playlist, &state);
155 return current_media_changed;
158 static void
159 vlc_playlist_ItemReplaced(vlc_playlist_t *playlist, size_t index)
161 struct vlc_playlist_state state;
162 vlc_playlist_state_Save(playlist, &state);
164 playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
165 playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
167 vlc_playlist_Notify(playlist, on_items_updated, index,
168 &playlist->items.data[index], 1);
169 vlc_playlist_state_NotifyChanges(playlist, &state);
172 size_t
173 vlc_playlist_Count(vlc_playlist_t *playlist)
175 vlc_playlist_AssertLocked(playlist);
176 return playlist->items.size;
179 vlc_playlist_item_t *
180 vlc_playlist_Get(vlc_playlist_t *playlist, size_t index)
182 vlc_playlist_AssertLocked(playlist);
183 return playlist->items.data[index];
186 ssize_t
187 vlc_playlist_IndexOf(vlc_playlist_t *playlist, const vlc_playlist_item_t *item)
189 vlc_playlist_AssertLocked(playlist);
191 ssize_t index;
192 vlc_vector_index_of(&playlist->items, item, &index);
193 return index;
196 ssize_t
197 vlc_playlist_IndexOfMedia(vlc_playlist_t *playlist, const input_item_t *media)
199 vlc_playlist_AssertLocked(playlist);
201 playlist_item_vector_t *items = &playlist->items;
202 for (size_t i = 0; i < items->size; ++i)
203 if (items->data[i]->media == media)
204 return i;
205 return -1;
208 void
209 vlc_playlist_Clear(vlc_playlist_t *playlist)
211 vlc_playlist_AssertLocked(playlist);
213 int ret = vlc_player_SetCurrentMedia(playlist->player, NULL);
214 VLC_UNUSED(ret); /* what could we do? */
216 vlc_playlist_ClearItems(playlist);
217 vlc_playlist_ItemsReset(playlist);
220 static int
221 vlc_playlist_MediaToItems(input_item_t *const media[], size_t count,
222 vlc_playlist_item_t *items[])
224 size_t i;
225 for (i = 0; i < count; ++i)
227 items[i] = vlc_playlist_item_New(media[i]);
228 if (unlikely(!items[i]))
229 break;
231 if (i < count)
233 /* allocation failure, release partial items */
234 while (i)
235 vlc_playlist_item_Release(items[--i]);
236 return VLC_ENOMEM;
238 return VLC_SUCCESS;
242 vlc_playlist_Insert(vlc_playlist_t *playlist, size_t index,
243 input_item_t *const media[], size_t count)
245 vlc_playlist_AssertLocked(playlist);
246 assert(index <= playlist->items.size);
248 /* make space in the vector */
249 if (!vlc_vector_insert_hole(&playlist->items, index, count))
250 return VLC_ENOMEM;
252 /* create playlist items in place */
253 int ret = vlc_playlist_MediaToItems(media, count,
254 &playlist->items.data[index]);
255 if (ret != VLC_SUCCESS)
257 /* we were optimistic, it failed, restore the vector state */
258 vlc_vector_remove_slice(&playlist->items, index, count);
259 return ret;
262 vlc_playlist_ItemsInserted(playlist, index, count);
263 vlc_player_InvalidateNextMedia(playlist->player);
265 return VLC_SUCCESS;
268 void
269 vlc_playlist_Move(vlc_playlist_t *playlist, size_t index, size_t count,
270 size_t target)
272 vlc_playlist_AssertLocked(playlist);
273 assert(index + count <= playlist->items.size);
274 assert(target + count <= playlist->items.size);
276 vlc_vector_move_slice(&playlist->items, index, count, target);
278 vlc_playlist_ItemsMoved(playlist, index, count, target);
279 vlc_player_InvalidateNextMedia(playlist->player);
282 void
283 vlc_playlist_Remove(vlc_playlist_t *playlist, size_t index, size_t count)
285 vlc_playlist_AssertLocked(playlist);
286 assert(index < playlist->items.size);
288 vlc_playlist_ItemsRemoving(playlist, index, count);
290 for (size_t i = 0; i < count; ++i)
291 vlc_playlist_item_Release(playlist->items.data[index + i]);
293 vlc_vector_remove_slice(&playlist->items, index, count);
295 bool current_media_changed = vlc_playlist_ItemsRemoved(playlist, index,
296 count);
297 if (current_media_changed)
298 vlc_playlist_SetCurrentMedia(playlist, playlist->current);
299 else
300 vlc_player_InvalidateNextMedia(playlist->player);
303 static int
304 vlc_playlist_Replace(vlc_playlist_t *playlist, size_t index,
305 input_item_t *media)
307 vlc_playlist_AssertLocked(playlist);
308 assert(index < playlist->items.size);
310 vlc_playlist_item_t *item = vlc_playlist_item_New(media);
311 if (!item)
312 return VLC_ENOMEM;
314 if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM)
316 randomizer_Remove(&playlist->randomizer,
317 &playlist->items.data[index], 1);
318 randomizer_Add(&playlist->randomizer, &item, 1);
321 vlc_playlist_item_Release(playlist->items.data[index]);
322 playlist->items.data[index] = item;
324 vlc_playlist_ItemReplaced(playlist, index);
325 return VLC_SUCCESS;
329 vlc_playlist_Expand(vlc_playlist_t *playlist, size_t index,
330 input_item_t *const media[], size_t count)
332 vlc_playlist_AssertLocked(playlist);
333 assert(index < playlist->items.size);
335 if (count == 0)
336 vlc_playlist_RemoveOne(playlist, index);
337 else
339 int ret = vlc_playlist_Replace(playlist, index, media[0]);
340 if (ret != VLC_SUCCESS)
341 return ret;
343 if (count > 1)
345 /* make space in the vector */
346 if (!vlc_vector_insert_hole(&playlist->items, index + 1, count - 1))
347 return VLC_ENOMEM;
349 /* create playlist items in place */
350 ret = vlc_playlist_MediaToItems(&media[1], count - 1,
351 &playlist->items.data[index + 1]);
352 if (ret != VLC_SUCCESS)
354 /* we were optimistic, it failed, restore the vector state */
355 vlc_vector_remove_slice(&playlist->items, index + 1, count - 1);
356 return ret;
358 vlc_playlist_ItemsInserted(playlist, index + 1, count - 1);
361 if ((ssize_t) index == playlist->current)
362 vlc_playlist_SetCurrentMedia(playlist, playlist->current);
363 else
364 vlc_player_InvalidateNextMedia(playlist->player);
367 return VLC_SUCCESS;