1 /*******************************************************************************
2 * Goggles Music Manager *
3 ********************************************************************************
4 * Copyright (C) 2007-2021 by Sander Jansen. All Rights Reserved *
5 * --- *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
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 General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see http://www.gnu.org/licenses. *
18 ********************************************************************************/
19 #include "gmdefs.h"
20 #include "gmutils.h"
21 #include <fxkeys.h>
22 #include "GMTrack.h"
23 #include "GMApp.h"
24 #include "GMList.h"
25 #include "GMCoverCache.h"
26 #include "GMAlbumList.h"
27 #include "GMTrackList.h"
28 #include "GMTrackView.h"
29 #include "GMSource.h"
30 #include "GMPlayerManager.h"
31 #include "GMIconTheme.h"
32 #include "GMClipboard.h"
33 #include "GMSourceView.h"
34 #include "GMColumnDialog.h"
35 #include "GMDatabaseSource.h"
36 #include "GMPlayListSource.h"
37 #include "GMPlayQueue.h"
38 #include "GMWindow.h"
39
40
41 #define HIDEBROWSER (FX4Splitter::ExpandBottomLeft)
42 #define SHOWBROWSER (FX4Splitter::ExpandTopLeft|FX4Splitter::ExpandTopRight|FX4Splitter::ExpandBottomLeft)
43
44
begins_with_keyword(const FXString & t)45 static inline FXbool begins_with_keyword(const FXString & t){
46 for (FXint i=0;i<GMPlayerManager::instance()->getPreferences().gui_sort_keywords.no();i++){
47 if (comparecase(t,GMPlayerManager::instance()->getPreferences().gui_sort_keywords[i],GMPlayerManager::instance()->getPreferences().gui_sort_keywords[i].length())==0) return true;
48 }
49 return false;
50 }
51
52
53 enum {
54 VIEW_BROWSER_LEFT = 0x1,
55 VIEW_BROWSER_MIDDLE = 0x2,
56 VIEW_BROWSER_RIGHT = 0x4,
57 VIEW_LIST = 0x8,
58 VIEW_BROWSER = 0x10,
59 };
60
61
62
63 static FXint album_selectionchanged=-1;
64 static FXint artist_selectionchanged=-1;
65 static FXint tag_selectionchanged=-1;
66
67 FXbool GMTrackView::reverse_artist=false;
68 FXbool GMTrackView::reverse_album=false;
69 FXbool GMTrackView::album_by_year=true;
70
71 class GMStaticMenuCheck : public GMMenuCheck {
72 FXDECLARE(GMStaticMenuCheck)
73 protected:
74 GMStaticMenuCheck();
75 private:
76 GMStaticMenuCheck(const GMStaticMenuCheck&);
77 GMStaticMenuCheck &operator=(const GMStaticMenuCheck&);
78 public:
79 long onButtonRelease(FXObject*,FXSelector,void*);
80 long onKeyRelease(FXObject*,FXSelector,void*);
81 public:
82 GMStaticMenuCheck(FXComposite* p,const FXString& text,FXObject* tgt=nullptr,FXSelector sel=0,FXuint opts=0);
83 virtual ~GMStaticMenuCheck();
84 };
85
86 FXDEFMAP(GMStaticMenuCheck) GMStaticMenuCheckMap[]={
87 FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,GMStaticMenuCheck::onButtonRelease),
88 FXMAPFUNC(SEL_KEYRELEASE,0,GMStaticMenuCheck::onKeyRelease)
89 };
90
FXIMPLEMENT(GMStaticMenuCheck,GMMenuCheck,GMStaticMenuCheckMap,ARRAYNUMBER (GMStaticMenuCheckMap))91 FXIMPLEMENT(GMStaticMenuCheck,GMMenuCheck,GMStaticMenuCheckMap,ARRAYNUMBER(GMStaticMenuCheckMap))
92
93 GMStaticMenuCheck::GMStaticMenuCheck(){
94 }
95
GMStaticMenuCheck(FXComposite * p,const FXString & text,FXObject * tgt,FXSelector sel,FXuint opts)96 GMStaticMenuCheck::GMStaticMenuCheck(FXComposite* p,const FXString& text,FXObject* tgt,FXSelector sel,FXuint opts) : GMMenuCheck(p,text,tgt,sel,opts) {
97 }
98
~GMStaticMenuCheck()99 GMStaticMenuCheck::~GMStaticMenuCheck(){
100 }
101
102
103 // Released button
onButtonRelease(FXObject *,FXSelector,void *)104 long GMStaticMenuCheck::onButtonRelease(FXObject*,FXSelector,void*){
105 FXbool active=isActive();
106 if(!isEnabled()) return 0;
107 if(active){
108 setCheck(!check);
109 if(target){ target->tryHandle(this,FXSEL(SEL_COMMAND,message),(void*)(FXuval)check); }
110 }
111 return 1;
112 }
113
114 // Keyboard release
onKeyRelease(FXObject *,FXSelector,void * ptr)115 long GMStaticMenuCheck::onKeyRelease(FXObject*,FXSelector,void* ptr){
116 FXEvent* event=(FXEvent*)ptr;
117 if(isEnabled() && (flags&FLAG_PRESSED)){
118 FXTRACE((200,"%s::onKeyRelease %p keysym=0x%04x state=%04x\n",getClassName(),this,event->code,event->state));
119 if(event->code==KEY_space || event->code==KEY_KP_Space || event->code==KEY_Return || event->code==KEY_KP_Enter){
120 flags&=~FLAG_PRESSED;
121 setCheck(!check);
122 if(target) target->tryHandle(this,FXSEL(SEL_COMMAND,message),(void*)(FXuval)check);
123 return 1;
124 }
125 }
126 return 0;
127 }
128
129
130 FXDEFMAP(GMTrackView) GMTrackViewMap[]={
131 FXMAPFUNC(SEL_UPDATE,GMTrackView::ID_TOGGLE_BROWSER,GMTrackView::onUpdToggleBrowser),
132 FXMAPFUNC(SEL_UPDATE,GMTrackView::ID_TOGGLE_TAGS,GMTrackView::onUpdToggleTags),
133 FXMAPFUNC(SEL_UPDATE,GMTrackView::ID_TOGGLE_FILTER,GMTrackView::onUpdToggleFilter),
134
135 FXMAPFUNC(SEL_UPDATE,GMTrackView::ID_COPY,GMTrackView::onUpdCopy),
136 FXMAPFUNC(SEL_UPDATE,GMTrackView::ID_PASTE,GMTrackView::onUpdPaste),
137 FXMAPFUNC(SEL_UPDATE,GMTrackView::ID_SHOW_CURRENT,GMTrackView::onUpdShowCurrent),
138
139 FXMAPFUNCS(SEL_UPDATE,GMTrackView::ID_FILTER_TRACK,GMTrackView::ID_FILTER_LAST,GMTrackView::onUpdFilterMask),
140 FXMAPFUNCS(SEL_COMMAND,GMTrackView::ID_FILTER_TRACK,GMTrackView::ID_FILTER_LAST,GMTrackView::onCmdFilterMask),
141
142
143 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_ARTIST_LIST_HEADER,GMTrackView::onCmdSortArtistList),
144 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_ALBUM_LIST_HEADER,GMTrackView::onCmdSortAlbumList),
145 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_TAG_LIST_HEADER,GMTrackView::onCmdSortTagList),
146 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_TOGGLE_BROWSER,GMTrackView::onCmdToggleBrowser),
147 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_TOGGLE_TAGS,GMTrackView::onCmdToggleTags),
148 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_TOGGLE_FILTER,GMTrackView::onCmdToggleFilter),
149 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_CLOSE_FILTER,GMTrackView::onCmdToggleFilter),
150
151 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_COPY,GMTrackView::onCmdCopy),
152 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_PASTE,GMTrackView::onCmdPaste),
153 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_SHOW_CURRENT,GMTrackView::onCmdShowCurrent),
154
155 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_FILTER,GMTrackView::onCmdFilter),
156 FXMAPFUNC(SEL_CHANGED,GMTrackView::ID_FILTER,GMTrackView::onCmdFilter),
157 FXMAPFUNC(SEL_TIMEOUT,GMTrackView::ID_FILTER,GMTrackView::onCmdFilter),
158
159 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_FILTER_MODE,GMTrackView::onCmdFilter),
160
161
162 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_TAG_LIST,GMTrackView::onCmdTagSelected),
163 FXMAPFUNC(SEL_SELECTED,GMTrackView::ID_TAG_LIST,GMTrackView::onCmdTagSelected),
164 FXMAPFUNC(SEL_DESELECTED,GMTrackView::ID_TAG_LIST,GMTrackView::onCmdTagSelected),
165 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_ARTIST_LIST,GMTrackView::onCmdArtistSelected),
166 FXMAPFUNC(SEL_SELECTED,GMTrackView::ID_ARTIST_LIST,GMTrackView::onCmdArtistSelected),
167 FXMAPFUNC(SEL_DESELECTED,GMTrackView::ID_ARTIST_LIST,GMTrackView::onCmdArtistSelected),
168 FXMAPFUNC(SEL_DOUBLECLICKED,GMTrackView::ID_ARTIST_LIST,GMTrackView::onCmdArtistSelected),
169 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_ALBUM_LIST,GMTrackView::onCmdAlbumSelected),
170 FXMAPFUNC(SEL_SELECTED,GMTrackView::ID_ALBUM_LIST,GMTrackView::onCmdAlbumSelected),
171 FXMAPFUNC(SEL_DESELECTED,GMTrackView::ID_ALBUM_LIST,GMTrackView::onCmdAlbumSelected),
172 FXMAPFUNC(SEL_DOUBLECLICKED,GMTrackView::ID_ALBUM_LIST,GMTrackView::onCmdAlbumSelected),
173
174 FXMAPFUNC(SEL_RIGHTBUTTONRELEASE,GMTrackView::ID_TAG_LIST,GMTrackView::onTagContextMenu),
175 FXMAPFUNC(SEL_RIGHTBUTTONRELEASE,GMTrackView::ID_ARTIST_LIST,GMTrackView::onArtistContextMenu),
176 FXMAPFUNC(SEL_RIGHTBUTTONRELEASE,GMTrackView::ID_ALBUM_LIST,GMTrackView::onAlbumContextMenu),
177 FXMAPFUNC(SEL_RIGHTBUTTONRELEASE,GMTrackView::ID_TRACK_LIST,GMTrackView::onTrackContextMenu),
178 FXMAPFUNC(SEL_RIGHTBUTTONRELEASE,GMTrackView::ID_TRACK_LIST_HEADER,GMTrackView::onTrackHeaderContextMenu),
179 FXMAPFUNC(SEL_RIGHTBUTTONRELEASE,GMTrackView::ID_ALBUM_LIST_HEADER,GMTrackView::onAlbumContextMenu),
180
181
182 FXMAPFUNC(SEL_KEYPRESS,GMTrackView::ID_TAG_LIST,GMTrackView::onCmdTagKeyPress),
183 FXMAPFUNC(SEL_KEYPRESS,GMTrackView::ID_ARTIST_LIST,GMTrackView::onCmdArtistKeyPress),
184 FXMAPFUNC(SEL_KEYPRESS,GMTrackView::ID_ALBUM_LIST,GMTrackView::onCmdAlbumKeyPress),
185 FXMAPFUNC(SEL_KEYPRESS,GMTrackView::ID_TRACK_LIST,GMTrackView::onCmdTrackKeyPress),
186
187
188 FXMAPFUNC(SEL_DOUBLECLICKED,GMTrackView::ID_TRACK_LIST,GMTrackView::onCmdPlayTrack),
189
190 FXMAPFUNC(SEL_BEGINDRAG,GMTrackView::ID_ARTIST_LIST,GMTrackView::onCmdBeginDrag),
191 FXMAPFUNC(SEL_BEGINDRAG,GMTrackView::ID_ALBUM_LIST,GMTrackView::onCmdBeginDrag),
192 FXMAPFUNC(SEL_BEGINDRAG,GMTrackView::ID_TRACK_LIST,GMTrackView::onCmdBeginDrag),
193
194 FXMAPFUNC(SEL_DRAGGED,GMTrackView::ID_ARTIST_LIST,GMTrackView::onCmdDragged),
195 FXMAPFUNC(SEL_DRAGGED,GMTrackView::ID_ALBUM_LIST,GMTrackView::onCmdDragged),
196 FXMAPFUNC(SEL_DRAGGED,GMTrackView::ID_TRACK_LIST,GMTrackView::onCmdDragged),
197
198 FXMAPFUNC(SEL_ENDDRAG,GMTrackView::ID_ARTIST_LIST,GMTrackView::onCmdEndDrag),
199 FXMAPFUNC(SEL_ENDDRAG,GMTrackView::ID_ALBUM_LIST,GMTrackView::onCmdEndDrag),
200 FXMAPFUNC(SEL_ENDDRAG,GMTrackView::ID_TRACK_LIST,GMTrackView::onCmdEndDrag),
201
202 FXMAPFUNC(SEL_DND_ENTER,GMTrackView::ID_TRACK_LIST,GMTrackView::onDndTrackEnter),
203 FXMAPFUNC(SEL_DND_LEAVE,GMTrackView::ID_TRACK_LIST,GMTrackView::onDndTrackLeave),
204 FXMAPFUNC(SEL_DND_MOTION,GMTrackView::ID_TRACK_LIST,GMTrackView::onDndTrackMotion),
205 FXMAPFUNC(SEL_DND_DROP,GMTrackView::ID_TRACK_LIST,GMTrackView::onDndTrackDrop),
206
207
208 FXMAPFUNC(SEL_DND_MOTION,GMTrackView::ID_TAG_LIST,GMTrackView::onDndMotion),
209 FXMAPFUNC(SEL_DND_MOTION,GMTrackView::ID_ARTIST_LIST,GMTrackView::onDndMotion),
210 FXMAPFUNC(SEL_DND_MOTION,GMTrackView::ID_ALBUM_LIST,GMTrackView::onDndMotion),
211 FXMAPFUNC(SEL_DND_DROP,GMTrackView::ID_TAG_LIST,GMTrackView::onDndDrop),
212 FXMAPFUNC(SEL_DND_DROP,GMTrackView::ID_ARTIST_LIST,GMTrackView::onDndDrop),
213 FXMAPFUNC(SEL_DND_DROP,GMTrackView::ID_ALBUM_LIST,GMTrackView::onDndDrop),
214
215 FXMAPFUNC(SEL_DND_REQUEST,GMTrackView::ID_ARTIST_LIST,GMTrackView::onDndRequest),
216 FXMAPFUNC(SEL_DND_REQUEST,GMTrackView::ID_ALBUM_LIST,GMTrackView::onDndRequest),
217 FXMAPFUNC(SEL_DND_REQUEST,GMTrackView::ID_TRACK_LIST,GMTrackView::onDndRequest),
218
219 FXMAPFUNCS(SEL_COMMAND,GMTrackView::ID_COLUMN_FIRST,GMTrackView::ID_COLUMN_LAST,GMTrackView::onCmdShowColumn),
220 FXMAPFUNCS(SEL_UPDATE,GMTrackView::ID_COLUMN_FIRST,GMTrackView::ID_COLUMN_LAST,GMTrackView::onUpdShowColumn),
221 FXMAPFUNCS(SEL_COMMAND,GMTrackView::ID_SORT_FIRST,GMTrackView::ID_SORT_LAST,GMTrackView::onCmdSort),
222 FXMAPFUNCS(SEL_UPDATE,GMTrackView::ID_SORT_FIRST,GMTrackView::ID_SORT_LAST,GMTrackView::onUpdSort),
223 FXMAPFUNC(SEL_UPDATE,GMTrackView::ID_SORT_REVERSE,GMTrackView::onUpdSortReverse),
224 FXMAPFUNC(SEL_UPDATE,GMTrackView::ID_SORT_BROWSE,GMTrackView::onUpdSortBrowse),
225 FXMAPFUNC(SEL_UPDATE,GMTrackView::ID_SORT_SHUFFLE,GMTrackView::onUpdSortShuffle),
226
227 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_SORT_SHUFFLE,GMTrackView::onCmdSortShuffle),
228 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_SORT_BROWSE,GMTrackView::onCmdSortBrowse),
229 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_SORT_DEFAULT,GMTrackView::onCmdSortDefault),
230
231 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_ALBUMS_VIEW_LIST,GMTrackView::onCmdAlbumListView),
232 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_ALBUMS_VIEW_BROWSER,GMTrackView::onCmdAlbumListView),
233 FXMAPFUNC(SEL_UPDATE,GMTrackView::ID_ALBUMS_VIEW_LIST,GMTrackView::onUpdAlbumListView),
234 FXMAPFUNC(SEL_UPDATE,GMTrackView::ID_ALBUMS_VIEW_BROWSER,GMTrackView::onUpdAlbumListView),
235
236 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_COVERSIZE_SMALL,GMTrackView::onCmdCoverSize),
237 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_COVERSIZE_MEDIUM,GMTrackView::onCmdCoverSize),
238 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_COVERSIZE_BIG,GMTrackView::onCmdCoverSize),
239 FXMAPFUNC(SEL_UPDATE,GMTrackView::ID_COVERSIZE_SMALL,GMTrackView::onUpdCoverSize),
240 FXMAPFUNC(SEL_UPDATE,GMTrackView::ID_COVERSIZE_MEDIUM,GMTrackView::onUpdCoverSize),
241 FXMAPFUNC(SEL_UPDATE,GMTrackView::ID_COVERSIZE_BIG,GMTrackView::onUpdCoverSize),
242
243
244
245 FXMAPFUNC(SEL_COMMAND,GMTrackView::ID_CONFIGURE_COLUMNS,GMTrackView::onCmdConfigureColumns),
246 };
247
FXIMPLEMENT(GMTrackView,FXPacker,GMTrackViewMap,ARRAYNUMBER (GMTrackViewMap))248 FXIMPLEMENT(GMTrackView,FXPacker,GMTrackViewMap,ARRAYNUMBER(GMTrackViewMap))
249
250
251 GMTrackView::GMTrackView(FXComposite* p) : FXPacker(p,LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0,0,0,0,0),
252 shuffle_seed((FXuint)FXThread::time()),
253 filtermask(FILTER_DEFAULT) {
254
255 GMScrollFrame * sunkenframe;
256
257 updateFont();
258
259
260 filtermenu = new GMMenuPane(getShell(),POPUP_SHRINKWRAP);
261 new GMStaticMenuCheck(filtermenu,tr("Title"),this,ID_FILTER_TRACK);
262 new GMStaticMenuCheck(filtermenu,tr("Artist"),this,ID_FILTER_ARTIST);
263 new GMStaticMenuCheck(filtermenu,tr("Album"),this,ID_FILTER_ALBUM);
264 new GMStaticMenuCheck(filtermenu,tr("Tag"),this,ID_FILTER_TAG);
265
266
267 filterframe = new FXHorizontalFrame(this,LAYOUT_SIDE_TOP|LAYOUT_FILL_X|PACK_UNIFORM_HEIGHT,0,0,0,0,0,0,0,0);
268 new GMButton(filterframe,tr("\tClose Filter\tClose Filter"),GMIconTheme::instance()->icon_close,this,ID_CLOSE_FILTER,BUTTON_TOOLBAR|FRAME_RAISED|LAYOUT_RIGHT);
269 new FXMenuButton(filterframe,tr("&Find"),GMIconTheme::instance()->icon_find,filtermenu,MENUBUTTON_NOARROWS|FRAME_RAISED|MENUBUTTON_TOOLBAR|ICON_BEFORE_TEXT|LAYOUT_CENTER_Y);
270 filterfield = new GMTextField(filterframe,20,this,ID_FILTER,LAYOUT_FILL_X|FRAME_LINE);
271
272 browsersplit = new FX4Splitter(this,LAYOUT_FILL_X|LAYOUT_FILL_Y|FOURSPLITTER_TRACKING);
273 tagsplit = new FX4Splitter(browsersplit,FOURSPLITTER_TRACKING);
274 taglistframe = new GMScrollFrame(tagsplit);
275 taglistheader = new GMHeaderButton(taglistframe,tr("Tags\tPress to change sorting order\tPress to change sorting order"),nullptr,this,GMTrackView::ID_TAG_LIST_HEADER,LAYOUT_FILL_X|FRAME_RAISED|JUSTIFY_LEFT);
276 taglist = new GMList(taglistframe,this,ID_TAG_LIST,LAYOUT_FILL_X|LAYOUT_FILL_Y|LIST_EXTENDEDSELECT);
277
278 sunkenframe = new GMScrollFrame(tagsplit);
279 artistlistheader = new GMHeaderButton(sunkenframe,tr("Artists\tPress to change sorting order\tPress to change sorting order"),nullptr,this,GMTrackView::ID_ARTIST_LIST_HEADER,LAYOUT_FILL_X|FRAME_RAISED|JUSTIFY_LEFT);
280 artistlist = new GMList(sunkenframe,this,ID_ARTIST_LIST,LAYOUT_FILL_X|LAYOUT_FILL_Y|LIST_EXTENDEDSELECT);
281
282 sunkenframe = new GMScrollFrame(browsersplit);
283 albumlistheader = new GMHeaderButton(sunkenframe,tr("\tPress to change sorting order\tPress to change sorting order"),nullptr,this,GMTrackView::ID_ALBUM_LIST_HEADER,LAYOUT_FILL_X|FRAME_RAISED|JUSTIFY_LEFT);
284 albumlist = new GMAlbumList(sunkenframe,this,ID_ALBUM_LIST,LAYOUT_FILL_X|LAYOUT_FILL_Y|ALBUMLIST_EXTENDEDSELECT|ALBUMLIST_COLUMNS);
285
286 sunkenframe = new GMScrollFrame(browsersplit);
287 tracklist = new GMTrackList(sunkenframe,this,ID_TRACK_LIST,LAYOUT_FILL_X|LAYOUT_FILL_Y|TRACKLIST_EXTENDEDSELECT);
288
289 sortmenu = new GMMenuPane(getShell(),POPUP_SHRINKWRAP);
290 new GMMenuRadio(sortmenu,tr("Browse"),this,ID_SORT_BROWSE);
291 new GMMenuRadio(sortmenu,tr("Shuffle\tCtrl-R"),this,ID_SORT_SHUFFLE);
292 new FXMenuSeparator(sortmenu);
293
294 for (FXint i=ID_SORT_FIRST;i<ID_SORT_LAST;i++) {
295 new GMMenuRadio(sortmenu,FXString::null,this,i);
296 }
297
298 new FXMenuSeparator(sortmenu);
299 new GMMenuCheck(sortmenu,tr("Reverse"),this,ID_SORT_REVERSE);
300
301
302 columnmenu = new GMMenuPane(getShell(),POPUP_SHRINKWRAP);
303 new GMMenuCommand(columnmenu,tr("&Configure Columns…") ,nullptr,this,ID_CONFIGURE_COLUMNS);
304 new GMMenuCascade(columnmenu,tr("&Sort\t\tChange Sorting."),GMIconTheme::instance()->icon_sort,sortmenu);
305
306
307 gm_set_window_cursor(sortmenu,getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
308 gm_set_window_cursor(columnmenu,getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
309 gm_set_window_cursor(filtermenu,getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
310
311 taglist->setNumVisible(9);
312 artistlist->setNumVisible(9);
313
314 taglist->setThickFont(font_listhead);
315 artistlist->setThickFont(font_listhead);
316 albumlist->setListHeadFont(font_listhead);
317 tracklist->setActiveFont(font_listhead);
318
319 taglist->dropEnable();
320 artistlist->dropEnable();
321 albumlist->dropEnable();
322 tracklist->dropEnable();
323
324 taglist->setSortFunc(genre_list_sort);
325 artistlist->setSortFunc(generic_name_sort);
326 albumlist->setSortFunc(GMAlbumListItem::album_list_sort);
327
328 taglistheader->setArrowState(ARROW_DOWN);
329 artistlistheader->setArrowState(ARROW_DOWN);
330 albumlistheader->setArrowState(ARROW_DOWN);
331
332 browsersplit->setBarSize(7);
333 tagsplit->setBarSize(7);
334
335 view=0;
336
337 getShell()->getAccelTable()->addAccel("Ctrl-N",this,FXSEL(SEL_COMMAND,ID_SORT_DEFAULT));
338 updateColors();
339 }
340
~GMTrackView()341 GMTrackView::~GMTrackView(){
342 getApp()->removeTimeout(this,ID_FILTER);
343 }
344
345
hasBrowser() const346 FXbool GMTrackView::hasBrowser() const {
347 return view&VIEW_BROWSER;
348 }
349
configureView(FXuint nvw)350 void GMTrackView::configureView(FXuint nvw) {
351 FXint expand=0;
352
353 // Always Enabled
354 nvw|=VIEW_BROWSER_RIGHT|VIEW_LIST;
355
356 if (nvw&VIEW_BROWSER_LEFT)
357 expand|=FX4Splitter::ExpandTopLeft;
358
359 if (nvw&VIEW_BROWSER_MIDDLE)
360 expand|=FX4Splitter::ExpandTopRight;
361
362 tagsplit->setExpanded(expand);
363
364
365 if (nvw&VIEW_BROWSER) {
366 if (nvw&(VIEW_BROWSER_LEFT|VIEW_BROWSER_MIDDLE))
367 browsersplit->setExpanded(FX4Splitter::ExpandTopLeft|FX4Splitter::ExpandTopRight|FX4Splitter::ExpandBottomLeft);
368 else{
369 browsersplit->setExpanded(FX4Splitter::ExpandTopRight|FX4Splitter::ExpandBottomLeft);
370 }
371 }
372 else {
373 browsersplit->setExpanded(FX4Splitter::ExpandBottomLeft);
374 }
375
376
377 if ((nvw&(VIEW_BROWSER_LEFT|VIEW_BROWSER_MIDDLE))!=(view&(VIEW_BROWSER_LEFT|VIEW_BROWSER_MIDDLE))) {
378 // 1/3 | 1/3 | 1/3
379 if ((nvw&VIEW_BROWSER_MIDDLE) && (nvw&VIEW_BROWSER_LEFT)) {
380 tagsplit->setHSplit(5000);
381 browsersplit->setHSplit(6666);
382 }
383 // 1/3 | 2/3
384 else if ((nvw&VIEW_BROWSER_MIDDLE) || (nvw&VIEW_BROWSER_LEFT)) {
385 browsersplit->setHSplit(3333);
386 }
387 }
388 view=nvw;
389 }
390
391
focusNext()392 FXbool GMTrackView::focusNext() {
393 if (hasBrowser()) {
394 if (taglistframe->shown() && taglist->hasFocus()){
395 artistlist->setFocus();
396 artistlist->makeItemVisible(artistlist->getCurrentItem());
397 }
398 else if (artistlist->hasFocus()) {
399 albumlist->setFocus();
400 albumlist->makeItemVisible(albumlist->getCurrentItem());
401 }
402 else if (albumlist->hasFocus()){
403 tracklist->setFocus();
404 tracklist->makeItemVisible(tracklist->getCurrentItem());
405 }
406 else {
407 FXbool gotfocus = hasFocus();
408 if (taglistframe->shown()) {
409 taglist->setFocus();
410 taglist->makeItemVisible(taglist->getCurrentItem());
411 }
412 else {
413 artistlist->setFocus();
414 artistlist->makeItemVisible(artistlist->getCurrentItem());
415 }
416 return !gotfocus;
417 }
418 }
419 else {
420 if (!tracklist->hasFocus()) {
421 tracklist->setFocus();
422 tracklist->makeItemVisible(tracklist->getCurrentItem());
423 return true;
424 }
425 else {
426 return false;
427 }
428 }
429 return true;
430 }
431
432
selectNext()433 void GMTrackView::selectNext() {
434 FXint current = tracklist->getCurrentItem();
435 if (current==tracklist->getNumItems()-1)
436 current=0;
437 else
438 current+=1;
439
440 tracklist->killSelection();
441 tracklist->setCurrentItem(current);
442 tracklist->selectItem(current);
443 }
444
selectPrevious()445 void GMTrackView::selectPrevious() {
446 FXint current = tracklist->getCurrentItem();
447 if (current==0)
448 current=tracklist->getNumItems()-1;
449 else
450 current-=1;
451
452 tracklist->killSelection();
453 tracklist->setCurrentItem(current);
454 tracklist->selectItem(current);
455 }
456
457
init_track_context_menu(FXMenuPane * pane,FXbool selected)458 void GMTrackView::init_track_context_menu(FXMenuPane * pane,FXbool selected){
459 if (selected && source->track_context_menu(pane))
460 new FXMenuSeparator(pane);
461 new GMMenuCommand(pane,tr("&Configure Columns""…"),nullptr,this,GMTrackView::ID_CONFIGURE_COLUMNS);
462 new GMMenuCascade(pane,tr("&Sort\t\tChange Sorting."),GMIconTheme::instance()->icon_sort,sortmenu);
463 pane->create();
464 ewmh_change_window_type(sortmenu,WINDOWTYPE_DROPDOWN_MENU);
465 ewmh_change_window_type(pane,WINDOWTYPE_POPUP_MENU);
466 }
467
468
updateFont()469 void GMTrackView::updateFont() {
470 FXFontDesc fontdescription = getApp()->getNormalFont()->getFontDesc();
471 fontdescription.slant = FXFont::Italic;
472 fontdescription.weight = FXFont::Bold;
473 //fontdescription.size -= 10;
474
475 if (font_listhead) {
476 font_listhead->destroy();
477 font_listhead->setFontDesc(fontdescription);
478 font_listhead->create();
479 }
480 else {
481 font_listhead = new FXFont(getApp(),fontdescription);
482 font_listhead->create();
483 }
484 }
485
486
updateColors()487 void GMTrackView::updateColors(){
488 tracklist->setRowColor(GMPlayerManager::instance()->getPreferences().gui_row_color);
489 tracklist->setActiveColor(GMPlayerManager::instance()->getPreferences().gui_play_color);
490 tracklist->setActiveTextColor(GMPlayerManager::instance()->getPreferences().gui_playtext_color);
491 taglist->setRowColor(GMPlayerManager::instance()->getPreferences().gui_row_color);
492 artistlist->setRowColor(GMPlayerManager::instance()->getPreferences().gui_row_color);
493 }
494
updateIcons()495 void GMTrackView::updateIcons(){
496 /*
497 FXint i=0;
498 FXIcon * icon_genre = nullptr;
499 FXIcon * icon_artist = nullptr;
500 FXIcon * icon_album = nullptr;
501
502 if (GMPlayerManager::instance()->getPreferences().gui_show_browser_icons) {
503 icon_genre = GMIconTheme::instance()->icon_genre;
504 icon_artist = GMIconTheme::instance()->icon_artist;
505 icon_album = GMIconTheme::instance()->icon_album;
506 }
507
508 for (i=0;i<genrelist->getNumItems();i++){
509 genrelist->setItemIcon(i,icon_genre);
510 }
511
512 for (i=0;i<artistlist->getNumItems();i++){
513 artistlist->setItemIcon(i,icon_artist);
514 }
515
516 for (i=0;i<albumlist->getNumItems();i++){
517 albumlist->setItemIcon(i,icon_album);
518 }
519 */
520 }
521
updateTrackItem(FXint index)522 void GMTrackView::updateTrackItem(FXint index) {
523 tracklist->updateItem(index);
524 }
525
526
clear()527 void GMTrackView::clear() {
528 taglist->clearItems();
529 artistlist->clearItems();
530 albumlist->clearItems();
531 tracklist->clearItems();
532 tracklist->setActiveItem(-1);
533 }
534
535 // FIXME get rid of show parameter, we only call this function with false when
536 // notify_playback_finished() is called. When show==false we delay the marking of the active
537 // track until BOS event is fired from the player.
setActive(FXint item,FXbool showactive)538 void GMTrackView::setActive(FXint item,FXbool showactive/*=true*/) {
539 if (source && item>=0){
540 source->markCurrent(tracklist->getItem(item));
541 if (showactive) tracklist->setCurrentItem(item);
542 }
543 if (showactive) tracklist->setActiveItem(item);
544 }
545
setCurrent(FXint item)546 void GMTrackView::setCurrent(FXint item) {
547 tracklist->setCurrentItem(item);
548 }
549
showCurrent()550 void GMTrackView::showCurrent() {
551 source->findCurrent(tracklist,GMPlayerManager::instance()->getSource());
552 }
553
getPreviousPlayable(FXint from,FXbool wrap) const554 FXint GMTrackView::getPreviousPlayable(FXint from,FXbool wrap) const {
555 FXint i;
556 for (i=from;i>=0;i--){
557 if (tracklist->isItemPlayable(i)) {
558 if (tracklist->getActiveItem()!=i)
559 return i;
560 else
561 return -1;
562 }
563 }
564 if (wrap) {
565 for (i=tracklist->getNumItems()-1;i>from;i--){
566 if (tracklist->isItemPlayable(i)) {
567 if (tracklist->getActiveItem()!=i)
568 return i;
569 else
570 return -1;
571 }
572 }
573 }
574 return -1;
575 }
576
getNextPlayable(FXint from,FXbool wrap) const577 FXint GMTrackView::getNextPlayable(FXint from,FXbool wrap) const {
578 FXint i;
579 for (i=from;i<tracklist->getNumItems();i++){
580 if (tracklist->isItemPlayable(i)) {
581 if (tracklist->getActiveItem()!=i)
582 return i;
583 else
584 return -1;
585 }
586 }
587 if (wrap) {
588 for (i=0;i<from;i++){
589 if (tracklist->isItemPlayable(i)) {
590 if (tracklist->getActiveItem()!=i)
591 return i;
592 else
593 return -1;
594 }
595 }
596 }
597 return -1;
598 }
599
getActive() const600 FXint GMTrackView::getActive() const{
601 return tracklist->getActiveItem();
602 }
603
getCurrent() const604 FXint GMTrackView::getCurrent() const{
605 if (GMPlayerManager::instance()->getPlayQueue()) {
606 FXIntList tracks;
607 tracks.append(tracklist->getItemId(tracklist->getCurrentItem()));
608 GMPlayerManager::instance()->getPlayQueue()->addTracks(source,tracks);
609 return GMPlayerManager::instance()->getPlayQueue()->getCurrent();
610 }
611 else {
612 return tracklist->getCurrentItem();
613 }
614 }
615
616 //generates a psuedo-random integer between min and max
617 extern int randint(int min, int max,unsigned int * random_seed);
618
getNext(FXbool wrap)619 FXint GMTrackView::getNext(FXbool wrap){
620 if (tracklist->getNumItems()==0) {
621 return -1;
622 }
623 else if (tracklist->getNumItems()>2 && GMPlayerManager::instance()->getPreferences().play_shuffle) {
624 if (tracklist->getActiveItem()>=0){
625 for (FXint i=0,track=0;i<10;i++) {
626 track = randint(0,tracklist->getNumItems()-1,&shuffle_seed);
627 if (track!=tracklist->getActiveItem()) return track;
628 }
629 }
630 return randint(0,tracklist->getNumItems()-1,&shuffle_seed);
631 }
632 return getNextPlayable(tracklist->getActiveItem()+1,(wrap||GMPlayerManager::instance()->getPreferences().play_repeat==REPEAT_ALL));
633 }
634
getPrevious()635 FXint GMTrackView::getPrevious(){
636 if (tracklist->getNumItems()==0) {
637 return -1;
638 }
639 else if (tracklist->getNumItems()>2 && GMPlayerManager::instance()->getPreferences().play_shuffle) {
640 if (tracklist->getActiveItem()>=0){
641 for (FXint i=0,track=0;i<10;i++) {
642 track = randint(0,tracklist->getNumItems()-1,&shuffle_seed);
643 if (track!=tracklist->getActiveItem()) return track;
644 }
645 }
646 return randint(0,tracklist->getNumItems()-1,&shuffle_seed);
647 }
648 return getPreviousPlayable(tracklist->getActiveItem()-1,(GMPlayerManager::instance()->getPreferences().play_repeat==REPEAT_ALL));
649 }
650
651
getTracks(FXIntList & tracks) const652 void GMTrackView::getTracks(FXIntList & tracks) const{
653 for (FXint i=0;i<tracklist->getNumItems();i++){
654 tracks.append(tracklist->getItemId(i));
655 }
656 }
657
658
659 // Function to sort by name, weight, slant, and size
compareindex(const void * a,const void * b)660 static int compareindex(const void *a,const void *b){
661 FXint * aa = (FXint*)a;
662 FXint * bb = (FXint*)b;
663 if ((*aa) > (*bb)) return 1;
664 else if ((*aa) < (*bb)) return -1;
665 return 0;
666 }
667
668
669
getSelectedTags(FXIntList & tags) const670 void GMTrackView::getSelectedTags(FXIntList & tags) const{
671 if (taglist->getNumItems()==1) {
672 if (taglist->isItemSelected(0) && ((FXint)(FXival)taglist->getItemData(0))!=-1)
673 tags.append((FXint)(FXival)taglist->getItemData(0));
674 }
675 else {
676 for (FXint i=1;i<taglist->getNumItems();i++){
677 if (taglist->isItemSelected(i)) {
678 tags.append((FXint)(FXival)taglist->getItemData(i));
679 }
680 }
681 }
682 qsort(tags.data(),tags.no(),sizeof(FXint),compareindex);
683 }
684
685
getSelectedArtists(FXIntList & artists) const686 void GMTrackView::getSelectedArtists(FXIntList & artists) const{
687 if (artistlist->getNumItems()==1) {
688 if (artistlist->isItemSelected(0) && ((FXint)(FXival)artistlist->getItemData(0))!=-1)
689 artists.append((FXint)(FXival)artistlist->getItemData(0));
690 }
691 else {
692 for (FXint i=1;i<artistlist->getNumItems();i++){
693 if (artistlist->isItemSelected(i)) {
694 artists.append((FXint)(FXival)artistlist->getItemData(i));
695 }
696 }
697 }
698 qsort(artists.data(),artists.no(),sizeof(FXint),compareindex);
699 }
700
701
getSelectedAlbums(FXIntList & albums) const702 void GMTrackView::getSelectedAlbums(FXIntList & albums) const{
703 FXint i=0;
704 if (albumlist->getNumItems()) {
705 if (albumlist->getItemId(0)==-1) {
706 if (albumlist->isItemSelected(0)){
707 for (i=1;i<albumlist->getNumItems();i++){
708 albums.append(albumlist->getItem(i)->getId());
709 }
710 }
711 else {
712 for (i=1;i<albumlist->getNumItems();i++){
713 if (albumlist->isItemSelected(i)) {
714 albums.append(albumlist->getItem(i)->getId());
715 }
716 }
717 }
718 }
719 else {
720 for (i=0;i<albumlist->getNumItems();i++){
721 if (albumlist->isItemSelected(i)) {
722 albums.append(albumlist->getItem(i)->getId());
723 }
724 }
725 }
726 }
727 qsort(albums.data(),albums.no(),sizeof(FXint),compareindex);
728 }
729
730
731
732
getSelectedTracks(FXIntList & tracks) const733 void GMTrackView::getSelectedTracks(FXIntList & tracks) const{
734 for (FXint i=0;i<tracklist->getNumItems();i++){
735 if (tracklist->isItemSelected(i)) {
736 tracks.append(tracklist->getItemId(i));
737 }
738 }
739 }
740
741
numTrackSelected() const742 FXint GMTrackView::numTrackSelected() const {
743 FXint num=0;
744 for (FXint i=0;i<tracklist->getNumItems();i++){
745 if (tracklist->isItemSelected(i)) num++;
746 }
747 return num;
748 }
749
trackSelected() const750 FXbool GMTrackView::trackSelected() const {
751 for (FXint i=0;i<tracklist->getNumItems();i++){
752 if (tracklist->isItemSelected(i)) return true;
753 }
754 return false;
755 }
756
757
hasTracks() const758 FXbool GMTrackView::hasTracks() const {
759 return tracklist->getNumItems()>0;
760 }
761
selectTagItem(FXint item)762 void GMTrackView::selectTagItem(FXint item) {
763 taglist->killSelection(true);
764 taglist->selectItem(item,true);
765 taglist->setCurrentItem(item,true);
766 handle(this,FXSEL(SEL_COMMAND,ID_TAG_LIST),(void*)(FXival)item);
767 }
768
769
selectArtistItem(FXint item)770 void GMTrackView::selectArtistItem(FXint item) {
771 artistlist->killSelection(true);
772 artistlist->selectItem(item,true);
773 artistlist->setCurrentItem(item,true);
774 handle(this,FXSEL(SEL_COMMAND,ID_ARTIST_LIST),(void*)(FXival)item);
775 }
776
777
selectAlbumItem(FXint item)778 void GMTrackView::selectAlbumItem(FXint item) {
779 albumlist->killSelection(true);
780 albumlist->selectItem(item,true);
781 albumlist->setCurrentItem(item,true);
782 handle(this,FXSEL(SEL_COMMAND,ID_ALBUM_LIST),(void*)(FXival)item);
783 }
784
785
selectTrackItem(FXint item)786 void GMTrackView::selectTrackItem(FXint item) {
787 tracklist->killSelection();
788 tracklist->selectItem(item);
789 tracklist->setCurrentItem(item);
790 }
791
792
setSource(GMSource * src)793 void GMTrackView::setSource(GMSource * src) {
794 if (source!=src) {
795
796 if (source) {
797
798 source->save(tracklist);
799
800 saveSettings(source->settingKey());
801
802 if (hasBrowser()){
803 saveSelection(taglist,"genre-list-selection",source->settingKey());
804 saveSelection(artistlist,"artist-list-selection",source->settingKey());
805 saveSelection(albumlist,"album-list-selection",source->settingKey());
806 }
807 }
808
809 source=src;
810
811 if (source) {
812
813 columns.clear();
814 source->configure(columns);
815
816 loadSettings(source->settingKey());
817
818
819 //source->show(tracklist);
820
821 clear();
822
823 if (hasBrowser()) {
824 listTags();
825 initSelection(taglist,"genre-list-selection",source->settingKey());
826 listArtists();
827 initSelection(artistlist,"artist-list-selection",source->settingKey());
828 listAlbums();
829 initSelection(albumlist,"album-list-selection",source->settingKey());
830 listTracks();
831 }
832 else {
833 listTracks();
834 }
835
836 tracklist->setPosition(tracklist_posx,tracklist_posy);
837 }
838 }
839 }
840
saveSelection(GMList * list,const char * key,const FXString & section) const841 void GMTrackView::saveSelection(GMList * list,const char * key,const FXString & section) const{
842 FXString value;
843 for (FXint i=0;i<list->getNumItems();i++){
844 if (list->isItemSelected(i))
845 value+=FXString::value(i)+";";
846 }
847 getApp()->reg().writeStringEntry(section.text(),key,value.text());
848 }
849
850
saveSelection(GMAlbumList * list,const char * key,const FXString & section) const851 void GMTrackView::saveSelection(GMAlbumList * list,const char * key,const FXString & section) const{
852 FXString value;
853 for (FXint i=0;i<list->getNumItems();i++){
854 if (list->isItemSelected(i))
855 value+=FXString::value(i)+";";
856 }
857 getApp()->reg().writeStringEntry(section.text(),key,value.text());
858 }
859
860
initSelection(GMList * list,const FXchar * key,const FXString & section)861 void GMTrackView::initSelection(GMList * list,const FXchar * key,const FXString & section){
862 FXint i=0,x=0,nselected=0;
863 FXString part;
864 FXString selection = getApp()->reg().readStringEntry(section.text(),key,"");
865 if (!selection.empty()){
866 list->killSelection(false);
867 part=selection.section(';',i);
868 while(!part.empty()){
869 x = part.toInt();
870 if (x>=0 && x<list->getNumItems()){
871 nselected++;
872 list->selectItem(x);
873 if (i==0) list->makeItemVisible(x);
874 }
875 part=selection.section(';',++i);
876 }
877 if (nselected==0 && list->getNumItems()){
878 list->selectItem(0);
879 }
880 }
881 }
882
883
initSelection(GMAlbumList * list,const FXchar * key,const FXString & section)884 void GMTrackView::initSelection(GMAlbumList * list,const FXchar * key,const FXString & section){
885 FXint i=0,x=0,nselected=0;
886 FXString part;
887 FXString selection = getApp()->reg().readStringEntry(section.text(),key,"");
888 if (!selection.empty()){
889 list->killSelection(false);
890 part=selection.section(';',i);
891 while(!part.empty()){
892 x = part.toInt();
893 if (x>=0 && x<list->getNumItems()){
894 nselected++;
895 list->selectItem(x);
896 if (i==0) list->makeItemVisible(x);
897 }
898 part=selection.section(';',++i);
899 }
900 if (nselected==0 && list->getNumItems()){
901 list->selectItem(0);
902 }
903 }
904 }
905
906
init(GMSource * src)907 void GMTrackView::init(GMSource * src) {
908 FXASSERT(source==nullptr);
909 FXASSERT(src);
910
911 source=src;
912
913
914 columns.clear();
915 source->configure(columns);
916
917 loadSettings(source->settingKey());
918
919 clear();
920
921 if (hasBrowser()) {
922 listTags();
923 initSelection(taglist,"genre-list-selection",source->settingKey());
924 listArtists();
925 initSelection(artistlist,"artist-list-selection",source->settingKey());
926 listAlbums();
927 initSelection(albumlist,"album-list-selection",source->settingKey());
928 listTracks();
929 }
930 else {
931 listTracks();
932 }
933
934 FXint active = getApp()->reg().readIntEntry("window","track-list-current",-1);
935 if (active>=0 && active<tracklist->getNumItems()) {
936 tracklist->setCurrentItem(active);
937 tracklist->selectItem(active);
938 }
939 tracklist->setPosition(tracklist_posx,tracklist_posy);
940 }
941
942
943
saveView() const944 void GMTrackView::saveView() const {
945 if (source) {
946
947 source->save(tracklist);
948
949 saveSettings(source->settingKey());
950
951 if (hasBrowser()){
952 saveSelection(taglist,"genre-list-selection",source->settingKey());
953 saveSelection(artistlist,"artist-list-selection",source->settingKey());
954 saveSelection(albumlist,"album-list-selection",source->settingKey());
955 }
956
957 getApp()->reg().writeIntEntry("window","track-list-current",tracklist->getActiveItem());
958 }
959 }
960
961
redrawAlbumList()962 void GMTrackView::redrawAlbumList() {
963 if (source) albumlist->setCoverCache(source->getCoverCache());
964 albumlist->update();
965 }
966
redrawTrackList()967 void GMTrackView::redrawTrackList() {
968 tracklist->update();
969 }
970
971
refreshUpdate()972 void GMTrackView::refreshUpdate() {
973 if (source) {
974 source->updateSelectedTracks(tracklist);
975 }
976 }
977
refresh(FXbool showplaying)978 void GMTrackView::refresh(FXbool showplaying/*=true*/) {
979 clear();
980
981 if (source) {
982 if (hasBrowser()) {
983 //GM_DEBUG_PRINT("begin refresh()\n");
984 listTags();
985 listArtists(showplaying);
986 listAlbums(showplaying);
987 listTracks();
988 //GM_DEBUG_PRINT("done\n");
989 }
990 else {
991 listTracks();
992 }
993 }
994
995 }
996
997
resort()998 void GMTrackView::resort() {
999 sortTags();
1000 sortArtists();
1001 sortAlbums();
1002 sortTracks();
1003 }
1004
1005
listTags()1006 FXbool GMTrackView::listTags() {
1007 if (source) {
1008
1009 if (!source->listTags(taglist,GMIconTheme::instance()->icon_genre))
1010 return false;
1011
1012 taglist->sortItems();
1013 if (taglist->getNumItems()>1)
1014 taglist->prependItem(FXString::value(fxtrformat("All %d Tags"),taglist->getNumItems()),GMIconTheme::instance()->icon_genre,(void*)(FXival)-1);
1015 else
1016 taglist->prependItem(tr("All Tags"),GMIconTheme::instance()->icon_genre,(void*)(FXival)-1);
1017
1018 taglist->setCurrentItem(0,false);
1019 taglist->selectItem(0,false);
1020 }
1021 return true;
1022 }
1023
1024
listArtists(FXbool showplaying)1025 FXbool GMTrackView::listArtists(FXbool showplaying/*=true*/){
1026 if (source) {
1027
1028 FXIntList tagselection;
1029
1030 getSelectedTags(tagselection);
1031
1032 if (!source->listArtists(artistlist,GMIconTheme::instance()->icon_artist,tagselection))
1033 return false;
1034
1035 artistlist->sortItems();
1036 if (artistlist->getNumItems()>1) {
1037 artistlist->prependItem(FXString::value(fxtrformat("All %d Artists"),artistlist->getNumItems()),GMIconTheme::instance()->icon_artist,(void*)(FXival)-1);
1038 }
1039
1040 if (showplaying && GMPlayerManager::instance()->playing() && GMPlayerManager::instance()->getSource()) {
1041 if (source->findCurrentArtist(artistlist,GMPlayerManager::instance()->getSource())) {
1042 return true;
1043 }
1044 }
1045
1046 if (artistlist->getNumItems()){
1047 artistlist->setCurrentItem(0,false);
1048 artistlist->selectItem(0,false);
1049 }
1050 }
1051 return true;
1052 }
1053
1054
listAlbums(FXbool showplaying)1055 FXbool GMTrackView::listAlbums(FXbool showplaying/*=true*/){
1056 if (source) {
1057
1058 FXIntList tagselection;
1059 FXIntList artistselection;
1060
1061 getSelectedTags(tagselection);
1062 getSelectedArtists(artistselection);
1063
1064 if (!source->listAlbums(albumlist,artistselection,tagselection))
1065 return false;
1066
1067 /*
1068 albumlist->sortItems();
1069
1070 if (albumlist->getNumItems()>1){
1071 albumlist->prependItem(new GMAlbumListItem(FXString::value(fxtrformat(source->getAlbumText()),albumlist->getNumItems()),FXString::value(fxtrformat("All %d Albums"),albumlist->getNumItems()),0,-1));
1072 }
1073 */
1074
1075
1076 if (showplaying && GMPlayerManager::instance()->playing() && GMPlayerManager::instance()->getSource()) {
1077 if (source->findCurrentAlbum(albumlist,GMPlayerManager::instance()->getSource())) {
1078 return true;
1079 }
1080 }
1081
1082 if (albumlist->getNumItems()) {
1083 albumlist->setCurrentItem(0,false);
1084 albumlist->selectItem(0,false);
1085 }
1086 }
1087 return true;
1088 }
1089
1090
listTracks()1091 FXbool GMTrackView::listTracks(){
1092 if (source) {
1093
1094 tracklist->setActiveItem(-1);
1095
1096 FXIntList tagselection;
1097 FXIntList albumselection;
1098
1099 if (hasBrowser()){
1100 getSelectedTags(tagselection);
1101 getSelectedAlbums(albumselection);
1102 if (albumselection.no()==0)
1103 return false;
1104 }
1105
1106 if (!source->listTracks(tracklist,albumselection,tagselection))
1107 return false;
1108
1109 layout();
1110
1111 tracklist->setCurrentItem(-1);
1112
1113 if (tracklist->getNumItems()) {
1114 sortTracks();
1115 if (tracklist->getCurrentItem()==-1)
1116 tracklist->setCurrentItem(0);
1117 }
1118 }
1119 return true;
1120 }
1121
1122
sortTags() const1123 void GMTrackView::sortTags() const{
1124 taglist->sortItems();
1125
1126 /// Make sure "All" is on top.
1127 FXint alltags=-1;
1128 FXint all = taglist->findItemByData((void*)(FXival)(FXint)alltags);
1129 if (all>0) {
1130 taglist->moveItem(0,all);
1131 }
1132 }
1133
sortArtists() const1134 void GMTrackView::sortArtists() const{
1135 artistlist->sortItems();
1136
1137 /// Make sure "All" is on top.
1138 FXint allartists=-1;
1139 FXint all = artistlist->findItemByData((void*)(FXival)(FXint)allartists);
1140 if (all>0) {
1141 artistlist->moveItem(0,all);
1142 }
1143 }
1144
sortAlbums() const1145 void GMTrackView::sortAlbums() const {
1146 albumlist->sortItems();
1147
1148 /// Make sure "All" is on top.
1149 FXint allalbums=-1;
1150 FXint all = albumlist->findItemById(allalbums);
1151 if (all>0) {
1152 albumlist->moveItem(0,all);
1153 }
1154 }
1155
sortTracks() const1156 void GMTrackView::sortTracks() const{
1157 if (tracklist->getSortMethod()==HEADER_SHUFFLE)
1158 source->shuffle(tracklist,sort_seed);
1159 else
1160 tracklist->sortItems();
1161
1162 if (GMPlayerManager::instance()->playing() && GMPlayerManager::instance()->getSource())
1163 source->findCurrent(tracklist,GMPlayerManager::instance()->getSource());
1164
1165 }
1166
setSortMethod(FXint def,FXbool reverse)1167 void GMTrackView::setSortMethod(FXint def,FXbool reverse) {
1168
1169 /// Tell source about pending sort
1170 source->sorted(tracklist,def);
1171
1172 if (def==HEADER_BROWSE) {
1173 tracklist->setSortMethod(HEADER_BROWSE);
1174 tracklist->setSortFunc(source->getSortBrowse(albumlist->getListStyle()&ALBUMLIST_BROWSER));
1175 }
1176 else if (def==HEADER_SHUFFLE) {
1177 tracklist->setSortMethod(HEADER_SHUFFLE);
1178 tracklist->setSortFunc(nullptr);
1179 }
1180 else {
1181 tracklist->setSortFunc(nullptr);
1182 for (FXint i=0;i<columns.no();i++){
1183 if (columns[i].type==def) {
1184 tracklist->setSortMethod(columns[i].type);
1185 if (reverse)
1186 tracklist->setSortFunc(columns[i].descending);
1187 else
1188 tracklist->setSortFunc(columns[i].ascending);
1189 break;
1190 }
1191 }
1192 }
1193 }
1194
getSortReverse() const1195 FXbool GMTrackView::getSortReverse() const {
1196 for (FXint i=0;i<columns.no();i++){
1197 if (columns[i].type==tracklist->getSortMethod()) {
1198 if (columns[i].descending==tracklist->getSortFunc())
1199 return true;
1200 break;
1201 }
1202 }
1203 return false;
1204 }
1205
1206
1207
loadSettings(const FXString & key)1208 void GMTrackView::loadSettings(const FXString & key) {
1209 FXASSERT(source);
1210
1211 FXbool sort_reverse,showui;
1212 FXint split,nvw=0;
1213
1214 sort_reverse = getApp()->reg().readBoolEntry(key.text(),"genre-list-sort-reverse",false);
1215 if (sort_reverse) {
1216 taglist->setSortFunc(genre_list_sort_reverse);
1217 taglistheader->setArrowState(ARROW_UP);
1218 }
1219 else {
1220 taglist->setSortFunc(genre_list_sort);
1221 taglistheader->setArrowState(ARROW_DOWN);
1222 }
1223
1224 reverse_artist = getApp()->reg().readBoolEntry(key.text(),"artist-list-sort-reverse",false);
1225 if (reverse_artist) {
1226 artistlist->setSortFunc(generic_name_sort_reverse);
1227 artistlistheader->setArrowState(ARROW_UP);
1228 }
1229 else {
1230 artistlist->setSortFunc(generic_name_sort);
1231 artistlistheader->setArrowState(ARROW_DOWN);
1232 }
1233
1234 if (getApp()->reg().readBoolEntry(key.text(),"album-list-browser",false)){
1235 FXuint opts=albumlist->getListStyle();
1236 albumlist->setListStyle(opts|ALBUMLIST_BROWSER);
1237 source->loadCovers();
1238 }
1239 else {
1240 FXuint opts=albumlist->getListStyle();
1241 albumlist->setListStyle(opts&~ALBUMLIST_BROWSER);
1242 }
1243
1244 albumlist->setListIcon(source->getAlbumIcon());
1245 albumlist->setCoverCache(source->getCoverCache());
1246
1247 if (getApp()->reg().readBoolEntry(key.text(),"album-list-show-year",true)){
1248 FXuint opts=albumlist->getListStyle();
1249 albumlist->setListStyle(opts|ALBUMLIST_YEAR);
1250 }
1251 else {
1252 FXuint opts=albumlist->getListStyle();
1253 albumlist->setListStyle(opts&~ALBUMLIST_YEAR);
1254 }
1255
1256 album_by_year = getApp()->reg().readBoolEntry(key.text(),"album-list-sort-by-year",false);
1257 reverse_album = getApp()->reg().readBoolEntry(key.text(),"album-list-sort-reverse",false);
1258
1259 if (albumlist->getListStyle()&ALBUMLIST_BROWSER) {
1260 if (reverse_album) {
1261 albumlist->setSortFunc(GMAlbumListItem::album_browser_sort_reverse);
1262 albumlistheader->setArrowState(ARROW_UP);
1263 }
1264 else {
1265 albumlist->setSortFunc(GMAlbumListItem::album_browser_sort);
1266 albumlistheader->setArrowState(ARROW_DOWN);
1267 }
1268 }
1269 else {
1270 if (reverse_album) {
1271 albumlist->setSortFunc(GMAlbumListItem::album_list_sort_reverse);
1272 albumlistheader->setArrowState(ARROW_UP);
1273 }
1274 else {
1275 albumlist->setSortFunc(GMAlbumListItem::album_list_sort);
1276 albumlistheader->setArrowState(ARROW_DOWN);
1277 }
1278 }
1279 albumlistheader->setText(source->getAlbumName());
1280
1281
1282
1283 if (getApp()->reg().readBoolEntry(key.text(),"genre-list",source->defaultTags()))
1284 nvw|=VIEW_BROWSER_LEFT;
1285
1286 showui = getApp()->reg().readBoolEntry(key.text(),"browser",source->defaultBrowse());
1287 if (showui && source->canBrowse())
1288 nvw|=VIEW_BROWSER;
1289
1290 if (source->hasArtistList())
1291 nvw|=VIEW_BROWSER_MIDDLE;
1292
1293 configureView(nvw);
1294
1295 split = getApp()->reg().readIntEntry(key.text(),"browser-track-split",-1);
1296 if (split!=-1) browsersplit->setVSplit(split);
1297
1298 split = getApp()->reg().readIntEntry(key.text(),"artist-album-split",-1);
1299 if (split!=-1) browsersplit->setHSplit(split);
1300
1301 split = getApp()->reg().readIntEntry(key.text(),"genre-artist-split",-1);
1302 if (split!=-1) tagsplit->setHSplit(split);
1303
1304 // split = getApp()->reg().readIntEntry(key.text(),"browser-split",-1);
1305 // if (split!=-1) setSplit(0,split);
1306
1307 tracklist_posx = getApp()->reg().readIntEntry(key.text(),"track-list-posx",0);
1308 tracklist_posy = getApp()->reg().readIntEntry(key.text(),"track-list-posy",0);
1309
1310 showui = getApp()->reg().readBoolEntry(key.text(),"filter",true);
1311 if (showui && source->canFilter())
1312 filterframe->show();
1313 else
1314 filterframe->hide();
1315
1316 filterfield->setText(getApp()->reg().readStringEntry(key.text(),"filter-text",""));
1317 if (getApp()->reg().existingEntry(key.text(),"filter-mode")) {
1318 FXuint mode = getApp()->reg().readIntEntry(key.text(),"filter-mode",0);
1319 switch(mode){
1320 case 0 : filtermask=FILTER_TRACK|FILTER_ALBUM|FILTER_ARTIST; break;
1321 case 1 : filtermask=FILTER_ARTIST; break;
1322 case 2 : filtermask=FILTER_ALBUM; break;
1323 case 3 : filtermask=FILTER_TRACK; break;
1324 default: filtermask=FILTER_DEFAULT; break;
1325 }
1326 getApp()->reg().deleteEntry(key.text(),"filter-mode");
1327 getApp()->reg().writeUIntEntry(key.text(),"filter-mask",filtermask);
1328 }
1329 else {
1330 filtermask = getApp()->reg().readUIntEntry(key.text(),"filter-mask",FILTER_DEFAULT);
1331 }
1332
1333 source->setFilter(filterfield->getText().trim().simplify(),filtermask);
1334
1335 loadTrackSettings(key);
1336 }
1337
1338
1339
loadTrackSettings(const FXString & key)1340 void GMTrackView::loadTrackSettings(const FXString & key) {
1341 FXString browseprefix = (hasBrowser()) ? "browse" : "list";
1342 FXString name;
1343 tracklist->clearHeaders();
1344 for (FXint i=0;i<columns.no();i++){
1345 name = columns[i].name;
1346 name.lower();
1347 columns[i].show = getApp()->reg().readBoolEntry(key.text(),FXString(browseprefix+"-showcolumn-"+name).text(),(hasBrowser()) ? columns[i].default_browser_show : columns[i].default_show);
1348 columns[i].size = getApp()->reg().readIntEntry(key.text(),FXString(browseprefix+"-columnwidth-"+name).text(),columns[i].size);
1349 columns[i].index = getApp()->reg().readIntEntry(key.text(),FXString(browseprefix+"-columnindex-"+name).text(),columns[i].index);
1350 if (columns[i].show) {
1351 tracklist->appendHeader(fxtr(columns[i].name.text()),columns[i].size,&columns[i]);
1352 }
1353 }
1354 FXint sort = getApp()->reg().readIntEntry(key.text(),FXString(browseprefix+"-sort-column").text(),source->getSortColumn(hasBrowser()));
1355 FXbool reverse = getApp()->reg().readBoolEntry(key.text(),FXString(browseprefix+"-sort-reverse").text(),false);
1356
1357 sort_seed = getApp()->reg().readUIntEntry(key.text(),FXString(browseprefix+"-sort-seed").text(),(FXuint)FXThread::time());
1358
1359 setSortMethod(sort,reverse);
1360 }
1361
1362
saveSettings(const FXString & key) const1363 void GMTrackView::saveSettings(const FXString & key) const {
1364 getApp()->reg().writeBoolEntry(key.text(),"genre-list-sort-reverse",taglist->getSortFunc()==genre_list_sort_reverse);
1365 getApp()->reg().writeBoolEntry(key.text(),"artist-list-sort-reverse",artistlist->getSortFunc()==generic_name_sort_reverse);
1366 getApp()->reg().writeBoolEntry(key.text(),"album-list-sort-reverse",albumlist->getSortFunc()==GMAlbumListItem::album_list_sort_reverse);
1367 getApp()->reg().writeBoolEntry(key.text(),"album-list-sort-by-year",album_by_year);
1368 getApp()->reg().writeBoolEntry(key.text(),"album-list-browser",(albumlist->getListStyle()&ALBUMLIST_BROWSER));
1369 getApp()->reg().writeBoolEntry(key.text(),"album-list-show-year",(albumlist->getListStyle()&ALBUMLIST_YEAR));
1370 getApp()->reg().writeBoolEntry(key.text(),"genre-list",taglistframe->shown());
1371 getApp()->reg().writeBoolEntry(key.text(),"browser",hasBrowser());
1372 getApp()->reg().writeIntEntry(key.text(),"browser-track-split",browsersplit->getVSplit());
1373 getApp()->reg().writeIntEntry(key.text(),"artist-album-split",browsersplit->getHSplit());
1374 getApp()->reg().writeIntEntry(key.text(),"genre-artist-split",tagsplit->getHSplit());
1375 getApp()->reg().writeIntEntry(key.text(),"track-list-posx",tracklist->getContentX());
1376 getApp()->reg().writeIntEntry(key.text(),"track-list-posy",tracklist->getContentY());
1377
1378 getApp()->reg().writeBoolEntry(key.text(),"filter",filterframe->shown());
1379
1380 if (filterframe->shown() && !filterfield->getText().empty()) {
1381 getApp()->reg().writeStringEntry(key.text(),"filter-text",filterfield->getText().text());
1382 getApp()->reg().writeUIntEntry(key.text(),"filter-mask",filtermask);
1383 }
1384 else{
1385 getApp()->reg().writeStringEntry(key.text(),"filter-text","");
1386 getApp()->reg().writeUIntEntry(key.text(),"filter-mask",FILTER_DEFAULT);
1387 }
1388
1389 saveTrackSettings(key);
1390 }
1391
1392
saveTrackSettings(const FXString & key) const1393 void GMTrackView::saveTrackSettings(const FXString & key) const {
1394 tracklist->saveHeaders();
1395 FXString browseprefix = (hasBrowser()) ? "browse" : "list";
1396 FXString name;
1397 for (FXint i=0;i<columns.no();i++){
1398 name = columns[i].name;
1399 getApp()->reg().writeBoolEntry(key.text(),FXString(browseprefix+"-showcolumn-"+name.lower()).text(),columns[i].show);
1400 getApp()->reg().writeIntEntry(key.text(),FXString(browseprefix+"-columnwidth-"+name.lower()).text(),columns[i].size);
1401 getApp()->reg().writeIntEntry(key.text(),FXString(browseprefix+"-columnindex-"+name.lower()).text(),columns[i].index);
1402 }
1403 getApp()->reg().writeIntEntry(key.text(),FXString(browseprefix+"-sort-column").text(),tracklist->getSortMethod());
1404 getApp()->reg().writeBoolEntry(key.text(),FXString(browseprefix+"-sort-reverse").text(),getSortReverse());
1405 getApp()->reg().writeUIntEntry(key.text(),FXString(browseprefix+"-sort-seed").text(),sort_seed);
1406 }
1407
1408
1409
onCmdShowColumn(FXObject *,FXSelector sel,void *)1410 long GMTrackView::onCmdShowColumn(FXObject*,FXSelector sel,void*){
1411 FXint no=FXSELID(sel)-ID_COLUMN_FIRST;
1412
1413 for (FXint i=0;i<columns.no();i++) {
1414 if (columns[i].index==no) {
1415 columns[i].show=!columns[i].show;
1416 }
1417 }
1418
1419 tracklist->clearHeaders();
1420 for (FXint i=0;i<columns.no();i++){
1421 if (columns[i].show) {
1422 tracklist->appendHeader(fxtr(columns[i].name.text()),columns[i].size,&columns[i]);
1423 }
1424 }
1425 return 1;
1426 }
1427
onUpdShowColumn(FXObject * sender,FXSelector sel,void *)1428 long GMTrackView::onUpdShowColumn(FXObject*sender,FXSelector sel,void*){
1429 if (columns.no()) {
1430 FXint no=FXSELID(sel)-ID_COLUMN_FIRST;
1431 for (FXint i=0;i<columns.no();i++) {
1432 if (columns[i].index==no) {
1433 FXString column = fxtr(columns[i].name.text());
1434 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETSTRINGVALUE),&column);
1435 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SHOW),nullptr);
1436 if (columns[i].show)
1437 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_CHECK),nullptr);
1438 else
1439 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),nullptr);
1440 return 1;
1441 }
1442 }
1443 }
1444 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_HIDE),nullptr);
1445 return 1;
1446 }
1447
1448
onCmdSort(FXObject *,FXSelector sel,void *)1449 long GMTrackView::onCmdSort(FXObject*,FXSelector sel,void*){
1450 FXint no=FXSELID(sel)-ID_SORT_FIRST;
1451 setSortMethod(columns[no].type);
1452 sortTracks();
1453 return 1;
1454 }
1455
1456
onUpdSort(FXObject * sender,FXSelector sel,void *)1457 long GMTrackView::onUpdSort(FXObject*sender,FXSelector sel,void*){
1458 if (columns.no()) {
1459 FXMenuCommand * cmd = dynamic_cast<FXMenuCommand*>(sender);
1460 FXASSERT(cmd);
1461 FXint no=FXSELID(sel)-ID_SORT_FIRST;
1462 if (no<columns.no()) {
1463 cmd->setText(FXString::value(fxtrformat("By %s"),fxtr(columns[no].name.text())));
1464 if (columns[no].type==source->getSortColumn(hasBrowser()))
1465 cmd->setAccelText("Ctrl-N");
1466 else
1467 cmd->setAccelText(FXString::null);
1468
1469 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SHOW),nullptr);
1470 if (tracklist->getSortMethod()==columns[no].type)
1471 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_CHECK),nullptr);
1472 else
1473 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),nullptr);
1474 }
1475 else {
1476 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_HIDE),nullptr);
1477 }
1478 }
1479 else
1480 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_HIDE),nullptr);
1481 return 1;
1482 }
1483
1484
onUpdSortReverse(FXObject * sender,FXSelector,void *)1485 long GMTrackView::onUpdSortReverse(FXObject*sender,FXSelector,void*){
1486 for (FXint i=0;i<columns.no();i++){
1487 if (tracklist->getSortMethod()==columns[i].type) {
1488 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),nullptr);
1489 if (tracklist->getSortFunc()==columns[i].descending)
1490 sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),nullptr);
1491 else
1492 sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),nullptr);
1493 return 1;
1494 }
1495 }
1496 sender->handle(this,FXSEL(SEL_COMMAND,ID_DISABLE),nullptr);
1497 return 1;
1498 }
1499
onCmdSortDefault(FXObject *,FXSelector,void *)1500 long GMTrackView::onCmdSortDefault(FXObject*,FXSelector,void*){
1501 setSortMethod(source->getSortColumn(hasBrowser()));
1502 sortTracks();
1503 return 1;
1504 }
1505
1506
onCmdSortBrowse(FXObject *,FXSelector,void *)1507 long GMTrackView::onCmdSortBrowse(FXObject*,FXSelector,void*){
1508 setSortMethod(HEADER_BROWSE);
1509 sortTracks();
1510 return 1;
1511 }
1512
1513
onUpdSortBrowse(FXObject * sender,FXSelector,void *)1514 long GMTrackView::onUpdSortBrowse(FXObject*sender,FXSelector,void*){
1515 if ((hasBrowser()) && source && source->getSortBrowse(false)) {
1516 sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),nullptr);
1517 if (tracklist->getSortMethod()==HEADER_BROWSE)
1518 sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),nullptr);
1519 else
1520 sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),nullptr);
1521
1522 FXMenuCommand * cmd = dynamic_cast<FXMenuCommand*>(sender);
1523 FXASSERT(cmd);
1524 if (HEADER_BROWSE==source->getSortColumn(hasBrowser()))
1525 cmd->setAccelText("Ctrl-N");
1526 else
1527 cmd->setAccelText(FXString::null);
1528
1529 }
1530 else
1531 sender->handle(this,FXSEL(SEL_COMMAND,ID_HIDE),nullptr);
1532 return 1;
1533 }
1534
1535
onCmdSortShuffle(FXObject *,FXSelector,void *)1536 long GMTrackView::onCmdSortShuffle(FXObject*,FXSelector,void*){
1537 setSortMethod(HEADER_SHUFFLE);
1538 sort_seed = (FXuint)FXThread::time();
1539 sortTracks();
1540 return 1;
1541 }
1542
1543
onUpdSortShuffle(FXObject * sender,FXSelector,void *)1544 long GMTrackView::onUpdSortShuffle(FXObject*sender,FXSelector,void*){
1545 if (tracklist->getSortMethod()==HEADER_SHUFFLE)
1546 sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),nullptr);
1547 else
1548 sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),nullptr);
1549 return 1;
1550 }
1551
1552
onCmdSortTagList(FXObject *,FXSelector,void *)1553 long GMTrackView::onCmdSortTagList(FXObject*,FXSelector,void*){
1554 if (taglist->getSortFunc()==genre_list_sort) {
1555 taglist->setSortFunc(genre_list_sort_reverse);
1556 taglistheader->setArrowState(ARROW_UP);
1557 }
1558 else {
1559 taglist->setSortFunc(genre_list_sort);
1560 taglistheader->setArrowState(ARROW_DOWN);
1561 }
1562 sortTags();
1563 return 1;
1564 }
1565
onCmdSortArtistList(FXObject *,FXSelector,void *)1566 long GMTrackView::onCmdSortArtistList(FXObject*,FXSelector,void*){
1567 if (artistlist->getSortFunc()==generic_name_sort) {
1568 artistlist->setSortFunc(generic_name_sort_reverse);
1569 reverse_artist=true;
1570 artistlistheader->setArrowState(ARROW_UP);
1571 }
1572 else {
1573 artistlist->setSortFunc(generic_name_sort);
1574 reverse_artist=false;
1575 artistlistheader->setArrowState(ARROW_DOWN);
1576 }
1577
1578 sortArtists();
1579
1580 // Resort albums since we sort by artist in browser mode
1581 if (albumlist->getListStyle()&ALBUMLIST_BROWSER)
1582 sortAlbums();
1583
1584 if (tracklist->getSortMethod()==HEADER_BROWSE)
1585 sortTracks();
1586 return 1;
1587 }
1588
1589
setAlbumListSort()1590 void GMTrackView::setAlbumListSort() {
1591 if (albumlist->getListStyle()&ALBUMLIST_BROWSER) {
1592 if (reverse_album) {
1593 albumlist->setSortFunc(GMAlbumListItem::album_browser_sort_reverse);
1594 albumlistheader->setArrowState(ARROW_UP);
1595 }
1596 else {
1597 albumlist->setSortFunc(GMAlbumListItem::album_browser_sort);
1598 albumlistheader->setArrowState(ARROW_DOWN);
1599 }
1600 }
1601 else {
1602 if (reverse_album) {
1603 albumlist->setSortFunc(GMAlbumListItem::album_list_sort_reverse);
1604 albumlistheader->setArrowState(ARROW_UP);
1605 }
1606 else {
1607 albumlist->setSortFunc(GMAlbumListItem::album_list_sort);
1608 albumlistheader->setArrowState(ARROW_DOWN);
1609 }
1610 }
1611 }
1612
1613
onCmdSortAlbumList(FXObject *,FXSelector,void *)1614 long GMTrackView::onCmdSortAlbumList(FXObject*,FXSelector,void*){
1615 reverse_album=!reverse_album;
1616 setAlbumListSort();
1617 sortAlbums();
1618 if (tracklist->getSortMethod()==HEADER_BROWSE)
1619 sortTracks();
1620 return 1;
1621 }
1622
1623
onCmdTagSelected(FXObject *,FXSelector sel,void * ptr)1624 long GMTrackView::onCmdTagSelected(FXObject*,FXSelector sel,void*ptr){
1625 if ( FXSELTYPE(sel)==SEL_COMMAND ) {
1626 if (tag_selectionchanged>=0) {
1627 artistlist->clearItems();
1628 albumlist->clearItems();
1629 tracklist->clearItems();
1630 listArtists();
1631 listAlbums();
1632 listTracks();
1633 tag_selectionchanged=-1;
1634 }
1635 }
1636 else {
1637
1638 /*
1639 Make sure "All Tag" is not selected at the
1640 same time as the other items and vice-versa.
1641 */
1642
1643 if ( (FXSELTYPE(sel)==SEL_SELECTED) && taglist->getNumItems()>1 ){
1644 if (((FXint)(FXival)ptr)==0) {
1645 taglist->killSelection();
1646 taglist->selectItem(0);
1647 }
1648 else if (taglist->isItemSelected(0)){
1649 taglist->deselectItem(0);
1650 }
1651 }
1652
1653 if ((FXSELTYPE(sel)==SEL_DESELECTED) && taglist->getNumItems()==1){
1654 taglist->selectItem(0);
1655 return 1;
1656 }
1657
1658 if (tag_selectionchanged==(FXint)(FXival)ptr)
1659 tag_selectionchanged=-1;
1660 else
1661 tag_selectionchanged=(FXint)(FXival)ptr;
1662 }
1663 return 1;
1664 }
1665
1666
onCmdArtistSelected(FXObject *,FXSelector sel,void * ptr)1667 long GMTrackView::onCmdArtistSelected(FXObject*,FXSelector sel,void*ptr){
1668 if ( FXSELTYPE(sel)==SEL_DOUBLECLICKED) {
1669 if (GMPlayerManager::instance()->getPreferences().play_from_queue) {
1670 FXIntList tracks;
1671 getTracks(tracks);
1672 GMPlayerManager::instance()->getPlayQueue()->addTracks(source,tracks);
1673 }
1674 if (GMPlayerManager::instance()->can_play())
1675 GMPlayerManager::instance()->playItem(TRACK_CURRENT);
1676 }
1677 else if ( FXSELTYPE(sel)==SEL_COMMAND ) {
1678 if (artist_selectionchanged>=0) {
1679 albumlist->clearItems();
1680 tracklist->clearItems();
1681 listAlbums();
1682 listTracks();
1683 artist_selectionchanged=-1;
1684 }
1685 }
1686 else {
1687
1688 /*
1689 Make sure "All Artist" is not selected at the
1690 same time as the other items and vice-versa.
1691 */
1692
1693 if ( (FXSELTYPE(sel)==SEL_SELECTED) && artistlist->getNumItems()>1 ){
1694 if (((FXint)(FXival)ptr)==0) {
1695 artistlist->killSelection();
1696 artistlist->selectItem(0);
1697 }
1698 else if (artistlist->isItemSelected(0)){
1699 artistlist->deselectItem(0);
1700 }
1701 }
1702
1703 if ((FXSELTYPE(sel)==SEL_DESELECTED) && artistlist->getNumItems()==1){
1704 artistlist->selectItem(0);
1705 return 1;
1706 }
1707
1708
1709 if (artist_selectionchanged==(FXint)(FXival)ptr)
1710 artist_selectionchanged=-1;
1711 else
1712 artist_selectionchanged=(FXint)(FXival)ptr;
1713 }
1714 return 1;
1715 }
1716
1717
onCmdAlbumSelected(FXObject *,FXSelector sel,void * ptr)1718 long GMTrackView::onCmdAlbumSelected(FXObject*,FXSelector sel,void*ptr){
1719 if ( FXSELTYPE(sel)==SEL_DOUBLECLICKED) {
1720 if (GMPlayerManager::instance()->getPreferences().play_from_queue) {
1721 FXIntList tracks;
1722 getTracks(tracks);
1723 GMPlayerManager::instance()->getPlayQueue()->addTracks(source,tracks);
1724 }
1725 if (GMPlayerManager::instance()->can_play())
1726 GMPlayerManager::instance()->playItem(TRACK_CURRENT);
1727 }
1728 else if ( FXSELTYPE(sel)==SEL_COMMAND ) {
1729 if (album_selectionchanged>=0) {
1730 tracklist->clearItems();
1731 listTracks();
1732 album_selectionchanged=-1;
1733 }
1734 }
1735 else {
1736 /*
1737 Make sure "All Albums" is not selected at the
1738 same time as the other items and vice-versa.
1739 */
1740 if ( (FXSELTYPE(sel)==SEL_SELECTED) && albumlist->getNumItems()>1 ){
1741 if (((FXint)(FXival)ptr)==0) {
1742 albumlist->killSelection();
1743 albumlist->selectItem(0);
1744 }
1745 else if (albumlist->isItemSelected(0)){
1746 albumlist->deselectItem(0);
1747 }
1748 }
1749 if (album_selectionchanged==(FXint)(FXival)ptr)
1750 album_selectionchanged=-1;
1751 else
1752 album_selectionchanged=(FXint)(FXival)ptr;
1753 }
1754 return 1;
1755 }
1756
1757
onTagContextMenu(FXObject *,FXSelector,void * ptr)1758 long GMTrackView::onTagContextMenu(FXObject*,FXSelector,void*ptr){
1759 FXEvent * event = static_cast<FXEvent*>(ptr);
1760 if (source && !event->moved) {
1761 FXint item = taglist->getItemAt(event->win_x,event->win_y);
1762 if (item>=0 && getTag(item)!=-1) {
1763 GMMenuPane pane(this);
1764 if (source->genre_context_menu(&pane)) {
1765 selectTagItem(item);
1766 pane.create();
1767 ewmh_change_window_type(&pane,WINDOWTYPE_POPUP_MENU);
1768 pane.popup(nullptr,event->root_x+3,event->root_y+3);
1769 getApp()->runPopup(&pane);
1770 }
1771 }
1772 return 1;
1773 }
1774 return 0;
1775 }
1776
onArtistContextMenu(FXObject *,FXSelector,void * ptr)1777 long GMTrackView::onArtistContextMenu(FXObject*,FXSelector,void*ptr){
1778 FXEvent * event = static_cast<FXEvent*>(ptr);
1779 if (source && !event->moved) {
1780 FXint item = artistlist->getItemAt(event->win_x,event->win_y);
1781 if (item>=0 && getArtist(item)!=-1) {
1782 GMMenuPane pane(this);
1783 if (source->artist_context_menu(&pane)) {
1784 selectArtistItem(item);
1785 selectAlbumItem(0);
1786 pane.create();
1787 ewmh_change_window_type(&pane,WINDOWTYPE_POPUP_MENU);
1788 pane.popup(nullptr,event->root_x+3,event->root_y+3);
1789 getApp()->runPopup(&pane);
1790 }
1791 }
1792 return 1;
1793 }
1794 return 0;
1795 }
1796
1797
onAlbumContextMenu(FXObject *,FXSelector sel,void * ptr)1798 long GMTrackView::onAlbumContextMenu(FXObject*,FXSelector sel,void*ptr){
1799 FXEvent * event = static_cast<FXEvent*>(ptr);
1800 FXbool old = album_by_year;
1801 FXint old_size = GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size;
1802 FXbool liststyle = albumlist->getListStyle();
1803
1804 FXDataTarget target_yearsort(album_by_year);
1805 if (source && !event->moved) {
1806 GMMenuPane pane(this);
1807
1808 if (FXSELID(sel)==ID_ALBUM_LIST) {
1809 FXint item = albumlist->getItemAt(event->win_x,event->win_y);
1810 if (item>=0 && getAlbum(item)!=-1) {
1811 selectAlbumItem(item);
1812 source->album_context_menu(&pane);
1813 }
1814 }
1815 /*
1816 FIXME Dirty Hack. We need to get this info from the source really.
1817 */
1818 if (dynamic_cast<GMDatabaseSource*>(source)!=nullptr) {
1819 new GMMenuCheck(&pane,fxtr("Show Album Year"),albumlist,GMAlbumList::ID_YEAR);
1820 new GMMenuCheck(&pane,fxtr("Sort by Album Year"),&target_yearsort,FXDataTarget::ID_VALUE);
1821 new FXMenuSeparator(&pane);
1822 }
1823 new GMMenuRadio(&pane,fxtr("List View"),this,ID_ALBUMS_VIEW_LIST);
1824 new GMMenuRadio(&pane,fxtr("Cover View"),this,ID_ALBUMS_VIEW_BROWSER);
1825 if (albumlist->getListStyle()&ALBUMLIST_BROWSER) {
1826 new FXMenuSeparator(&pane),
1827 new GMMenuRadio(&pane,fxtr("Small Cover"), this,ID_COVERSIZE_SMALL),
1828 new GMMenuRadio(&pane,fxtr("Medium Cover"), this,ID_COVERSIZE_MEDIUM),
1829 new GMMenuRadio(&pane,fxtr("Big Cover"),this,ID_COVERSIZE_BIG),
1830 new FXMenuSeparator(&pane),
1831 new GMMenuRadio(&pane,fxtr("Arrange By Rows"),albumlist,GMAlbumList::ID_ARRANGE_BY_ROWS);
1832 new GMMenuRadio(&pane,fxtr("Arrange By Columns"),albumlist,GMAlbumList::ID_ARRANGE_BY_COLUMNS);
1833 }
1834 pane.create();
1835 pane.forceRefresh();
1836 ewmh_change_window_type(&pane,WINDOWTYPE_POPUP_MENU);
1837 pane.popup(nullptr,event->root_x+3,event->root_y+3);
1838 getApp()->runPopup(&pane);
1839
1840
1841 // Changing list styles changes sort methods for album and tracklist
1842 if ((albumlist->getListStyle()!=liststyle) || (old!=album_by_year)) {
1843 setAlbumListSort();
1844 sortAlbums();
1845 if (tracklist->getSortMethod()==HEADER_BROWSE) {
1846 tracklist->setSortFunc(source->getSortBrowse(albumlist->getListStyle()&ALBUMLIST_BROWSER));
1847 }
1848 sortTracks();
1849 }
1850
1851 if (old_size!=GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size){
1852 source->updateCovers();
1853 }
1854 return 1;
1855 }
1856 return 0;
1857 }
1858
1859
onTrackContextMenu(FXObject *,FXSelector,void * ptr)1860 long GMTrackView::onTrackContextMenu(FXObject*,FXSelector,void*ptr){
1861 FXEvent * event = static_cast<FXEvent*>(ptr);
1862 if (source && !event->moved) {
1863 FXint item = tracklist->getItemAt(event->win_x,event->win_y);
1864 GMMenuPane pane(this);
1865
1866 if (item>=0 && !tracklist->isItemSelected(item))
1867 selectTrackItem(item);
1868
1869 init_track_context_menu(&pane,(item>=0));
1870
1871 gm_run_popup_menu(&pane,event->root_x+3,event->root_y+3);
1872 return 1;
1873 }
1874 return 0;
1875 }
1876
1877
onTrackHeaderContextMenu(FXObject *,FXSelector,void * ptr)1878 long GMTrackView::onTrackHeaderContextMenu(FXObject*,FXSelector,void*ptr){
1879 FXEvent * event = static_cast<FXEvent*>(ptr);
1880 if (source && !event->moved) {
1881 columnmenu->create();
1882 ewmh_change_window_type(columnmenu,WINDOWTYPE_POPUP_MENU);
1883 columnmenu->popup(nullptr,event->root_x+3,event->root_y+3);
1884 getApp()->runPopup(columnmenu);
1885 return 1;
1886 }
1887 return 0;
1888 }
1889
1890
onCmdTagKeyPress(FXObject *,FXSelector,void * ptr)1891 long GMTrackView::onCmdTagKeyPress(FXObject*,FXSelector,void*ptr){
1892 FXEvent* event=static_cast<FXEvent*>(ptr);
1893 if (event->state&(CONTROLMASK) && (event->code==KEY_A || event->code==KEY_a)) {
1894 if (taglist->getNumItems()) {
1895 selectTagItem(0);
1896 taglist->makeItemVisible(0);
1897 }
1898 return 1;
1899 }
1900 else if (event->code==KEY_Delete || event->code==KEY_KP_Delete) {
1901 if (source && taglist->getNumItems()) {
1902 source->handle(this,FXSEL(SEL_COMMAND,GMSource::ID_DELETE_TAG),nullptr);
1903 }
1904 return 1;
1905 }
1906 // else if (event->code==KEY_F2) {
1907 // if (source && genrelist->getNumItems()) {
1908 // source->handle(this,FXSEL(SEL_COMMAND,GMSource::ID_EDIT_TAGS),nullptr);
1909 // }
1910 // return 1;
1911 // }
1912 return 0;
1913 }
1914
onCmdArtistKeyPress(FXObject *,FXSelector,void * ptr)1915 long GMTrackView::onCmdArtistKeyPress(FXObject*,FXSelector,void*ptr){
1916 FXEvent* event=static_cast<FXEvent*>(ptr);
1917 if (event->state&(CONTROLMASK) && (event->code==KEY_A || event->code==KEY_a)) {
1918 if (artistlist->getNumItems()) {
1919 selectArtistItem(0);
1920 artistlist->makeItemVisible(0);
1921 }
1922 return 1;
1923 }
1924 else if (event->code==KEY_Delete || event->code==KEY_KP_Delete) {
1925 if (source && artistlist->getNumItems()) {
1926 if (event->state&(SHIFTMASK))
1927 source->handle(this,FXSEL(SEL_COMMAND,GMSource::ID_DELETE_ARTIST_ADV),nullptr);
1928 else
1929 source->handle(this,FXSEL(SEL_COMMAND,GMSource::ID_DELETE_ARTIST),nullptr);
1930 }
1931 return 1;
1932 }
1933 /*
1934 else if (event->code==KEY_Menu) {
1935 FXDataTarget target_yearsort(album_by_year);
1936 GMMenuPane pane(this);
1937 new GMMenuCheck(&pane,fxtr("Sort by Album Year"),&target_yearsort,FXDataTarget::ID_VALUE);
1938 FXint rootx,rooty;
1939 albumlist->translateCoordinatesTo(rootx,rooty,getApp()->getRootWindow(),0,0);
1940 gm_run_popup_menu(&pane,rootx-1,rooty-1);
1941 return 1;
1942 }
1943 */
1944
1945 // else if (event->code==KEY_F2) {
1946 // if (source && artistlist->getNumItems()) {
1947 // source->handle(this,FXSEL(SEL_COMMAND,GMSource::ID_EDIT_ARTIST),nullptr);
1948 // }
1949 // return 1;
1950 // }
1951 else if (!(event->state&CONTROLMASK)){
1952 FXString text;
1953 FXint a;
1954 for (FXint i=0;i<artistlist->getNumItems();i++){
1955 text=artistlist->getItemText(i);
1956 if (begins_with_keyword(text))
1957 a=FXMIN(text.length()-1,text.find(' ')+1);
1958 else
1959 a=0;
1960 if (comparecase(&text[a],event->text,1)==0){
1961 selectArtistItem(i);
1962 artistlist->makeItemVisible(i);
1963 break;
1964 }
1965 }
1966 }
1967 return 0;
1968 }
1969
1970
onCmdAlbumKeyPress(FXObject *,FXSelector,void * ptr)1971 long GMTrackView::onCmdAlbumKeyPress(FXObject*,FXSelector,void*ptr){
1972 FXEvent* event=static_cast<FXEvent*>(ptr);
1973 if (event->state&(CONTROLMASK) && (event->code==KEY_A || event->code==KEY_a)) {
1974 if (albumlist->getNumItems()) {
1975 selectAlbumItem(0);
1976 albumlist->makeItemVisible(0);
1977 }
1978 return 1;
1979 }
1980 else if (event->code==KEY_Delete || event->code==KEY_KP_Delete) {
1981 if (source && albumlist->getNumItems()) {
1982 if (event->state&(SHIFTMASK))
1983 source->handle(this,FXSEL(SEL_COMMAND,GMSource::ID_DELETE_ALBUM_ADV),nullptr);
1984 else
1985 source->handle(this,FXSEL(SEL_COMMAND,GMSource::ID_DELETE_ALBUM),nullptr);
1986 }
1987 return 1;
1988 }
1989 else if (event->code==KEY_Menu) {
1990 #if 0
1991 FXDataTarget target_yearsort(album_by_year);
1992 GMMenuPane pane(this);
1993 new GMMenuCheck(&pane,fxtr("Sort by Album Year"),&target_yearsort,FXDataTarget::ID_VALUE);
1994 FXint rootx,rooty;
1995 albumlist->translateCoordinatesTo(rootx,rooty,getApp()->getRootWindow(),0,0);
1996 gm_run_popup_menu(&pane,rootx-1,rooty-1);
1997 #endif
1998 return 1;
1999 }
2000
2001
2002 // else if (event->code==KEY_F2) {
2003 // if (source && albumlist->getNumItems()) {
2004 // source->handle(this,FXSEL(SEL_COMMAND,GMSource::ID_EDIT_ALBUM),nullptr);
2005 // }
2006 // return 1;
2007 // }
2008 return 0;
2009 }
2010
2011
onCmdTrackKeyPress(FXObject *,FXSelector,void * ptr)2012 long GMTrackView::onCmdTrackKeyPress(FXObject*,FXSelector,void*ptr){
2013 FXEvent* event=static_cast<FXEvent*>(ptr);
2014 if (event->state&(CONTROLMASK) ) {
2015 if (event->code==KEY_A || event->code==KEY_a) {
2016 if (tracklist->getNumItems()){
2017 tracklist->setAnchorItem(0);
2018 tracklist->selectItem(0);
2019 tracklist->extendSelection(tracklist->getNumItems()-1);
2020 }
2021 return 1;
2022 }
2023 else if (event->code==KEY_C || event->code==KEY_c) {
2024 if (source && numTrackSelected() ) {
2025 source->handle(this,FXSEL(SEL_COMMAND,GMSource::ID_COPY_TRACK),nullptr);
2026 }
2027 return 1;
2028 }
2029 }
2030 else if (event->code==KEY_Delete || event->code==KEY_KP_Delete) {
2031 if (source && numTrackSelected() ) {
2032 if (event->state&(SHIFTMASK))
2033 source->handle(this,FXSEL(SEL_COMMAND,GMSource::ID_DELETE_TRACK_ADV),nullptr);
2034 else
2035 source->handle(this,FXSEL(SEL_COMMAND,GMSource::ID_DELETE_TRACK),nullptr);
2036 }
2037 return 1;
2038 }
2039 else if (event->code==KEY_F2) {
2040 if (source && numTrackSelected()) {
2041 source->handle(this,FXSEL(SEL_COMMAND,GMSource::ID_EDIT_TRACK),nullptr);
2042 }
2043 return 1;
2044 }
2045 else if (event->code==KEY_Menu) {
2046 GMMenuPane pane(this);
2047 init_track_context_menu(&pane,trackSelected());
2048 FXint rootx,rooty;
2049 tracklist->translateCoordinatesTo(rootx,rooty,getApp()->getRootWindow(),0,0);
2050 gm_run_popup_menu(&pane,rootx-1,rooty-1);
2051 return 1;
2052 }
2053
2054 else {
2055 // toggle filter and send keystroke to textfield
2056 //handle(this,FXSEL(SEL_COMMAND,ID_TOGGLE_FILTER),nullptr);
2057 }
2058 return 0;
2059 }
2060
2061
onCmdPlayTrack(FXObject *,FXSelector,void *)2062 long GMTrackView::onCmdPlayTrack(FXObject*,FXSelector,void*){
2063 if (!source->track_double_click()) {
2064 if (GMPlayerManager::instance()->getPlayQueue()) {
2065 if (GMPlayerManager::instance()->getPlayQueue()->canPlaySource(source)) {
2066 FXIntList tracks;
2067 tracks.append(tracklist->getItemId(tracklist->getCurrentItem()));
2068 GMPlayerManager::instance()->getPlayQueue()->addTracks(source,tracks);
2069 if (GMPlayerManager::instance()->can_play())
2070 GMPlayerManager::instance()->playItem(TRACK_CURRENT);
2071 }
2072 else {
2073 GMPlayerManager::instance()->setPlayQueue(false);
2074 if (GMPlayerManager::instance()->can_play())
2075 GMPlayerManager::instance()->playItem(TRACK_CURRENT);
2076 }
2077 }
2078 else {
2079 GMPlayerManager::instance()->playItem(TRACK_CURRENT);
2080 tracklist->deselectItem(tracklist->getCurrentItem());
2081 }
2082 }
2083 return 1;
2084 }
2085
onCmdShowCurrent(FXObject *,FXSelector,void *)2086 long GMTrackView::onCmdShowCurrent(FXObject*,FXSelector,void*){
2087 if (!source->findCurrent(tracklist,GMPlayerManager::instance()->getSource())){
2088 if (source->hasCurrentTrack(GMPlayerManager::instance()->getSource())){
2089 refresh();
2090 }
2091 else {
2092 GMPlayerManager::instance()->getSourceView()->setSource(GMPlayerManager::instance()->getSource());
2093 if (!source->findCurrent(tracklist,GMPlayerManager::instance()->getSource())){
2094 if (source->hasCurrentTrack(GMPlayerManager::instance()->getSource())){
2095 refresh();
2096 }
2097 }
2098 }
2099 }
2100 return 1;
2101 }
2102
onUpdShowCurrent(FXObject * sender,FXSelector,void *)2103 long GMTrackView::onUpdShowCurrent(FXObject*sender,FXSelector,void*){
2104 if (GMPlayerManager::instance()->playing() && GMPlayerManager::instance()->getSource())
2105 sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),nullptr);
2106 else
2107 sender->handle(this,FXSEL(SEL_COMMAND,ID_DISABLE),nullptr);
2108 return 1;
2109 }
2110
2111
onCmdPaste(FXObject * sender,FXSelector,void * ptr)2112 long GMTrackView::onCmdPaste(FXObject*sender,FXSelector,void*ptr){
2113 return source && source->handle(sender,FXSEL(SEL_COMMAND,GMSource::ID_PASTE),ptr);
2114 }
2115
onUpdPaste(FXObject * sender,FXSelector,void * ptr)2116 long GMTrackView::onUpdPaste(FXObject*sender,FXSelector,void*ptr){
2117 return source && source->handle(sender,FXSEL(SEL_UPDATE,GMSource::ID_PASTE),ptr);
2118 }
2119
2120
onCmdCopy(FXObject * sender,FXSelector,void * ptr)2121 long GMTrackView::onCmdCopy(FXObject*sender,FXSelector,void*ptr){
2122 return source && source->handle(sender,FXSEL(SEL_COMMAND,GMSource::ID_COPY_TRACK),ptr);
2123 }
2124
onUpdCopy(FXObject * sender,FXSelector,void *)2125 long GMTrackView::onUpdCopy(FXObject*sender,FXSelector,void*){
2126 if (trackSelected() && source)
2127 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_ENABLE),nullptr);
2128 else
2129 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_DISABLE),nullptr);
2130 return 1;
2131 }
2132
2133
onCmdFilter(FXObject *,FXSelector sel,void *)2134 long GMTrackView::onCmdFilter(FXObject*,FXSelector sel,void*){
2135 if (FXSELID(sel)==ID_FILTER_MODE && filterfield->getText().empty())
2136 return 1;
2137 if (FXSELTYPE(sel)==SEL_CHANGED) {
2138 getApp()->addTimeout(this,ID_FILTER,500_ms);
2139 return 1;
2140 }
2141 if (FXSELTYPE(sel)==SEL_COMMAND){
2142 getApp()->removeTimeout(this,ID_FILTER);
2143 }
2144 if (source->setFilter(filterfield->getText().trim().simplify(),filtermask))
2145 refresh(false);
2146 return 1;
2147 }
2148
onCmdFilterMask(FXObject *,FXSelector sel,void *)2149 long GMTrackView::onCmdFilterMask(FXObject*,FXSelector sel,void*){
2150 switch(FXSELID(sel)){
2151 case ID_FILTER_TRACK : filtermask ^= FILTER_TRACK; break;
2152 case ID_FILTER_ALBUM : filtermask ^= FILTER_ALBUM; break;
2153 case ID_FILTER_ARTIST : filtermask ^= FILTER_ARTIST; break;
2154 case ID_FILTER_TAG : filtermask ^= FILTER_TAG; break;
2155 }
2156 getApp()->addTimeout(this,ID_FILTER,500_ms);
2157 return 1;
2158 }
2159
2160
onUpdFilterMask(FXObject * sender,FXSelector sel,void *)2161 long GMTrackView::onUpdFilterMask(FXObject*sender,FXSelector sel,void*){
2162 FXbool check=false;
2163 switch(FXSELID(sel)){
2164 case ID_FILTER_TRACK : check = (filtermask&FILTER_TRACK)!=0; break;
2165 case ID_FILTER_ALBUM : check = (filtermask&FILTER_ALBUM)!=0; break;
2166 case ID_FILTER_ARTIST: check = (filtermask&FILTER_ARTIST)!=0; break;
2167 case ID_FILTER_TAG : check = (filtermask&FILTER_TAG)!=0; break;
2168 }
2169 if (check)
2170 sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),nullptr);
2171 else
2172 sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),nullptr);
2173 return 1;
2174 }
2175
2176
2177
onCmdBeginDrag(FXObject * sender,FXSelector sel,void *)2178 long GMTrackView::onCmdBeginDrag(FXObject*sender,FXSelector sel,void*){
2179 FXWindow * window = (FXWindow*)sender;
2180 if (FXSELID(sel)==ID_ALBUM_LIST) {
2181
2182 /* we don't seem to get a SEL_COMMAND message when we start dragging */
2183 if (album_selectionchanged>=0) {
2184 tracklist->clearItems();
2185 listTracks();
2186 album_selectionchanged=-1;
2187 }
2188
2189 FXDragType types[]={GMClipboard::kdeclipboard,GMClipboard::urilistType,GMClipboard::alltracks};
2190 if (window->beginDrag(types,3)){
2191 }
2192 }
2193 else if (FXSELID(sel)==ID_TRACK_LIST){
2194 FXDragType types[4];
2195 FXuint ntypes=source->dnd_provides(types);
2196 if (ntypes) window->beginDrag(types,ntypes);
2197 }
2198 else if (FXSELID(sel)==ID_ARTIST_LIST){
2199
2200 /* we don't seem to get a SEL_COMMAND message when we start dragging */
2201 if (artist_selectionchanged>=0) {
2202 albumlist->clearItems();
2203 tracklist->clearItems();
2204 listAlbums();
2205 listTracks();
2206 artist_selectionchanged=-1;
2207 }
2208 FXDragType types[]={GMClipboard::kdeclipboard,GMClipboard::urilistType,GMClipboard::alltracks};
2209 if (window->beginDrag(types,3)){
2210 }
2211 }
2212 else {
2213 return 0;
2214 }
2215 return 1;
2216 }
2217
onCmdDragged(FXObject * sender,FXSelector,void * ptr)2218 long GMTrackView::onCmdDragged(FXObject*sender,FXSelector,void*ptr){
2219 FXWindow * window = (FXWindow*)sender;
2220 FXEvent* event=(FXEvent*)ptr;
2221 FXDragAction action=DRAG_COPY;
2222 if(event->state&ALTMASK) action=DRAG_LINK;
2223 window->handleDrag(event->root_x,event->root_y,action);
2224 action=window->didAccept();
2225 if (window->didAccept()!=DRAG_REJECT) {
2226 if (action==DRAG_MOVE)
2227 window->setDragCursor(getApp()->getDefaultCursor(DEF_DNDMOVE_CURSOR));
2228 else if (action==DRAG_LINK)
2229 window->setDragCursor(getApp()->getDefaultCursor(DEF_DNDLINK_CURSOR));
2230 else
2231 window->setDragCursor(getApp()->getDefaultCursor(DEF_DNDCOPY_CURSOR));
2232 }
2233 else {
2234 window->setDragCursor(getApp()->getDefaultCursor(DEF_DNDSTOP_CURSOR));
2235 }
2236 return 1;
2237 }
2238
onCmdEndDrag(FXObject * sender,FXSelector,void *)2239 long GMTrackView::onCmdEndDrag(FXObject*sender,FXSelector,void*){
2240 FXWindow * window = (FXWindow*)sender;
2241 if (getApp()->getDragWindow()==tracklist)
2242 window->endDrag(window->didAccept()!=DRAG_REJECT);
2243 else
2244 window->endDrag((window->didAccept()!=DRAG_MOVE && window->didAccept()!=DRAG_REJECT));
2245 window->setDragCursor(window->getDefaultCursor());
2246 return 1;
2247 }
2248
2249
onDndTrackEnter(FXObject *,FXSelector,void *)2250 long GMTrackView::onDndTrackEnter(FXObject*,FXSelector,void*){
2251 tracklist_dragging=1;
2252 tracklist_lastline=-1;
2253 return 0;
2254 }
2255
2256
onDndTrackLeave(FXObject *,FXSelector,void *)2257 long GMTrackView::onDndTrackLeave(FXObject*,FXSelector,void*){
2258 tracklist_dragging=0;
2259 if (tracklist_lastline>=0) {
2260 tracklist->update(0,tracklist_lastline,tracklist->getHeader()->getDefaultWidth(),1);
2261 }
2262 tracklist_lastline=-1;
2263 return 0;
2264 }
2265
2266
onDndTrackMotion(FXObject *,FXSelector,void * ptr)2267 long GMTrackView::onDndTrackMotion(FXObject*,FXSelector,void*ptr){
2268 FXEvent* event=(FXEvent*)ptr;
2269 if (getApp()->getDragWindow()==tracklist) {
2270 if (tracklist->offeredDNDType(FROM_DRAGNDROP,GMClipboard::selectedtracks)){
2271 FXint pos_x,pos_y,item;
2272 tracklist->getPosition(pos_x,pos_y);
2273
2274 item = (event->win_y-pos_y-tracklist->getHeader()->getDefaultHeight())/tracklist->getLineHeight();
2275
2276 if (item<0) item=0;
2277 if (item>=tracklist->getNumItems()) {
2278 tracklist->acceptDrop(DRAG_REJECT);
2279 return 1;
2280 }
2281
2282 FXint ds = pos_y+item*tracklist->getLineHeight()+tracklist->getHeader()->getDefaultHeight();
2283 FXint dm = ds + (tracklist->getLineHeight()/2);
2284 FXint dl=0;
2285
2286 tracklist_dropitem=item;
2287
2288 if (event->win_y<=dm) {
2289 dl = ds;
2290 }
2291 else {
2292 dl = ds+tracklist->getLineHeight();
2293 tracklist_dropitem=FXMIN(item+1,tracklist->getNumItems());
2294 }
2295
2296 FXDCWindow dc(tracklist);
2297 dc.setForeground(FXRGB(0,0,0));
2298 dc.fillRectangle(0,dl,tracklist->getHeader()->getDefaultWidth(),1);
2299
2300 if (tracklist_lastline>=0 && (tracklist_lastline!=dl || tracklist_lastposy!=pos_y)) {
2301 tracklist->update(0,tracklist_lastline-(tracklist_lastposy-pos_y),tracklist->getHeader()->getDefaultWidth(),1);
2302 }
2303
2304 tracklist_lastline=dl;
2305 tracklist_lastposy=pos_y;
2306
2307 tracklist->acceptDrop(DRAG_ACCEPT);
2308 return 1;
2309 }
2310 }
2311 else if (getApp()->getDragWindow()==nullptr) {
2312 FXDragType * types;
2313 FXuint ntypes;
2314 if (tracklist->inquireDNDTypes(FROM_DRAGNDROP,types,ntypes)){
2315 if (source->dnd_accepts(types,ntypes)){
2316 tracklist->acceptDrop(DRAG_ACCEPT);
2317 freeElms(types);
2318 return 1;
2319 }
2320 }
2321 freeElms(types);
2322 }
2323 tracklist->acceptDrop(DRAG_REJECT);
2324 return 1;
2325 }
2326
2327
2328
2329
onDndTrackDrop(FXObject * sender,FXSelector,void * ptr)2330 long GMTrackView::onDndTrackDrop(FXObject*sender,FXSelector,void*ptr){
2331 if (getApp()->getDragWindow()==tracklist) {
2332
2333 if (!tracklist->offeredDNDType(FROM_DRAGNDROP,GMClipboard::selectedtracks)) return 1;
2334
2335 if (tracklist_lastline>=0) {
2336 tracklist->update(0,tracklist_lastline,tracklist->getHeader()->getDefaultWidth(),1);
2337 }
2338
2339 tracklist_dragging=1;
2340 tracklist_lastline=-1;
2341
2342 FXint i,tgt;
2343 FXbool moved=false;
2344 for (i=tracklist->getNumItems()-1;i>=0;i--){
2345 if (tracklist->isItemSelected(i) && (i+1)!=tracklist_dropitem) {
2346 if (i<tracklist_dropitem) tgt=tracklist_dropitem-1; else tgt=tracklist_dropitem;
2347 tracklist->moveItem(tgt,i);
2348 tracklist->deselectItem(tgt);
2349 if (i<tracklist_dropitem) tracklist_dropitem-=1;
2350 i+=1;
2351 moved=true;
2352 }
2353 }
2354
2355 if (moved) {
2356 source->dragged(tracklist);
2357 }
2358
2359 tracklist->dropFinished(DRAG_LINK);
2360
2361 if (GMPlayerManager::instance()->playing() && GMPlayerManager::instance()->getSource())
2362 source->findCurrent(tracklist,GMPlayerManager::instance()->getSource());
2363
2364 return 1;
2365 }
2366 else if (source && getApp()->getDragWindow()==nullptr) {
2367 return source->handle(sender,FXSEL(SEL_DND_DROP,GMSource::ID_DROP),ptr);
2368 }
2369 return 0;
2370 }
2371
2372
onDndMotion(FXObject *,FXSelector,void *)2373 long GMTrackView::onDndMotion(FXObject*,FXSelector,void*){
2374 if (getApp()->getDragWindow()==nullptr && source) {
2375 FXDragType * types;
2376 FXuint ntypes;
2377 if (tracklist->inquireDNDTypes(FROM_DRAGNDROP,types,ntypes)){
2378 if (source->dnd_accepts(types,ntypes)){
2379 tracklist->acceptDrop(DRAG_ACCEPT);
2380 freeElms(types);
2381 return 1;
2382 }
2383 }
2384 freeElms(types);
2385 }
2386 return 0;
2387 }
2388
onDndDrop(FXObject * sender,FXSelector,void * ptr)2389 long GMTrackView::onDndDrop(FXObject*sender,FXSelector,void*ptr){
2390 if (getApp()->getDragWindow()==nullptr && source) {
2391 return source->handle(sender,FXSEL(SEL_DND_DROP,GMSource::ID_DROP),ptr);
2392 }
2393 return 0;
2394 }
2395
onDndRequest(FXObject * sender,FXSelector sel,void * ptr)2396 long GMTrackView::onDndRequest(FXObject*sender,FXSelector sel,void*ptr){
2397 if (source) {
2398 switch(FXSELID(sel)){
2399 case ID_TRACK_LIST : return source->handle(sender,FXSEL(SEL_DND_REQUEST,GMSource::ID_COPY_TRACK),ptr); break;
2400 case ID_ALBUM_LIST : return source->handle(sender,FXSEL(SEL_DND_REQUEST,GMSource::ID_COPY_ALBUM),ptr); break;
2401 case ID_ARTIST_LIST: return source->handle(sender,FXSEL(SEL_DND_REQUEST,GMSource::ID_COPY_ARTIST),ptr); break;
2402 default : break;
2403 }
2404 }
2405 return 0;
2406 }
2407
2408
onCmdToggleBrowser(FXObject *,FXSelector,void *)2409 long GMTrackView::onCmdToggleBrowser(FXObject*,FXSelector,void*){
2410 if (source && source->canBrowse()) {
2411
2412 saveTrackSettings(source->settingKey());
2413
2414 configureView(view^VIEW_BROWSER);
2415
2416 loadTrackSettings(source->settingKey());
2417
2418 refresh();
2419 }
2420 return 1;
2421 }
2422
onUpdToggleBrowser(FXObject * sender,FXSelector,void *)2423 long GMTrackView::onUpdToggleBrowser(FXObject*sender,FXSelector,void*){
2424 if (source && source->canBrowse()) {
2425 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_ENABLE),nullptr);
2426 if (hasBrowser())
2427 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_CHECK),nullptr);
2428 else
2429 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),nullptr);
2430 }
2431 else {
2432 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),nullptr);
2433 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_DISABLE),nullptr);
2434 }
2435 return 1;
2436 }
2437
2438
2439
2440
2441
2442
2443
onCmdToggleTags(FXObject *,FXSelector,void *)2444 long GMTrackView::onCmdToggleTags(FXObject*,FXSelector,void*){
2445 if (hasBrowser()) {
2446 configureView(view^VIEW_BROWSER_LEFT);
2447 if (!(view&VIEW_BROWSER_LEFT)) {
2448 selectTagItem(0);
2449 }
2450 }
2451 return 1;
2452 }
2453
onUpdToggleTags(FXObject * sender,FXSelector,void *)2454 long GMTrackView::onUpdToggleTags(FXObject*sender,FXSelector,void*){
2455 if (source && source->canBrowse() && hasBrowser()) {
2456 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_ENABLE),nullptr);
2457 if (taglistframe->shown())
2458 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_CHECK),nullptr);
2459 else
2460 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),nullptr);
2461 }
2462 else {
2463 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),nullptr);
2464 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_DISABLE),nullptr);
2465 }
2466 return 1;
2467 }
2468
onCmdToggleFilter(FXObject *,FXSelector sel,void *)2469 long GMTrackView::onCmdToggleFilter(FXObject*,FXSelector sel,void*){
2470 if (filterframe->shown() && FXSELID(sel)==ID_CLOSE_FILTER) {
2471 filterframe->hide();
2472 if (!filterfield->getText().empty()){
2473 source->setFilter(FXString::null,filtermask);
2474 refresh(false);
2475 }
2476 recalc();
2477 }
2478 else {
2479 filterframe->show();
2480 filterfield->setFocus();
2481 if (!filterfield->getText().empty()){
2482 filterfield->setSelection(0,filterfield->getText().length());
2483 getApp()->addTimeout(this,ID_FILTER,500_ms);
2484 }
2485 recalc();
2486 }
2487 return 1;
2488 }
2489
onUpdToggleFilter(FXObject * sender,FXSelector,void *)2490 long GMTrackView::onUpdToggleFilter(FXObject*sender,FXSelector,void*){
2491 if (source && source->canFilter())
2492 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_ENABLE),nullptr);
2493 else
2494 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_DISABLE),nullptr);
2495 return 1;
2496 }
2497
2498
onCmdAlbumListView(FXObject *,FXSelector sel,void *)2499 long GMTrackView::onCmdAlbumListView(FXObject*,FXSelector sel,void*){
2500 if (FXSELID(sel)==ID_ALBUMS_VIEW_LIST) {
2501 FXuint opts=albumlist->getListStyle();
2502 albumlist->setListStyle(opts&~ALBUMLIST_BROWSER);
2503 }
2504 else {
2505 FXuint opts=albumlist->getListStyle();
2506 albumlist->setListStyle(opts|ALBUMLIST_BROWSER);
2507 if (source) {
2508 source->loadCovers();
2509 GMPlayerManager::instance()->getTrackView()->redrawAlbumList();
2510 }
2511 }
2512 return 1;
2513 }
onUpdAlbumListView(FXObject * sender,FXSelector sel,void *)2514 long GMTrackView::onUpdAlbumListView(FXObject*sender,FXSelector sel,void*){
2515 if (FXSELID(sel)==ID_ALBUMS_VIEW_LIST) {
2516 FXuint opts=albumlist->getListStyle();
2517 if (opts&ALBUMLIST_BROWSER)
2518 sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),nullptr);
2519 else
2520 sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),nullptr);
2521 }
2522 else {
2523 FXuint opts=albumlist->getListStyle();
2524 if (opts&ALBUMLIST_BROWSER)
2525 sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),nullptr);
2526 else
2527 sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),nullptr);
2528 }
2529 return 1;
2530 }
2531
2532
onCmdCoverSize(FXObject *,FXSelector sel,void *)2533 long GMTrackView::onCmdCoverSize(FXObject*,FXSelector sel,void*){
2534 switch(FXSELID(sel)){
2535 case ID_COVERSIZE_SMALL : GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size = 128; break;
2536 case ID_COVERSIZE_MEDIUM : GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size = 160; break;
2537 case ID_COVERSIZE_BIG : GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size = 256; break;
2538 }
2539 return 1;
2540 }
2541
onUpdCoverSize(FXObject * sender,FXSelector sel,void *)2542 long GMTrackView::onUpdCoverSize(FXObject*sender,FXSelector sel,void*){
2543 FXbool check=false;
2544 const FXint size = GMPlayerManager::instance()->getPreferences().gui_coverdisplay_size;
2545 switch(FXSELID(sel)){
2546 case ID_COVERSIZE_SMALL : if (size <= 128) check = true; break;
2547 case ID_COVERSIZE_MEDIUM : if (size>128 && size<=160) check = true; break;
2548 case ID_COVERSIZE_BIG : if (size>160 && size<=256) check = true; break;
2549 }
2550 if (check)
2551 sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),nullptr);
2552 else
2553 sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),nullptr);
2554 return 1;
2555 }
2556
2557
onCmdConfigureColumns(FXObject *,FXSelector,void *)2558 long GMTrackView::onCmdConfigureColumns(FXObject*,FXSelector,void*){
2559 GMColumnDialog dialog(getShell(),columns);
2560 if (dialog.execute()) {
2561 dialog.saveIndex();
2562
2563 tracklist->clearHeaders();
2564 for (FXint i=0;i<columns.no();i++){
2565 if (columns[i].show) {
2566 tracklist->appendHeader(fxtr(columns[i].name.text()),columns[i].size,&columns[i]);
2567 }
2568 }
2569
2570
2571 }
2572 return 1;
2573 }
2574
2575
findTrackIndexById(FXint id) const2576 FXint GMTrackView::findTrackIndexById(FXint id) const {
2577 return tracklist->findItemById(id);
2578 }
2579
getTrackItem(FXint i) const2580 GMTrackItem * GMTrackView::getTrackItem(FXint i) const {
2581 return tracklist->getItem(i);
2582 }
2583
getCurrentTrackItem() const2584 GMTrackItem * GMTrackView::getCurrentTrackItem() const {
2585 FXASSERT(tracklist->getCurrentItem()>=0); return tracklist->getItem(tracklist->getCurrentItem());
2586 }
2587
isTrackItemSelected(FXint i) const2588 FXbool GMTrackView::isTrackItemSelected(FXint i) const {
2589 return tracklist->isItemSelected(i);
2590 }
2591
getNumTracks() const2592 FXint GMTrackView::getNumTracks() const {
2593 return tracklist->getNumItems() ;
2594 }
2595
getCurrentAlbumItem() const2596 GMAlbumListItem * GMTrackView::getCurrentAlbumItem() const {
2597 FXASSERT(tracklist->getCurrentItem()>=0); return dynamic_cast<GMAlbumListItem*>(albumlist->getItem(albumlist->getCurrentItem()));
2598 }
2599
2600
2601
getTag(FXint index) const2602 FXint GMTrackView::getTag(FXint index) const { return (FXint)(FXival)taglist->getItemData(index); }
2603
getArtist(FXint index) const2604 FXint GMTrackView::getArtist(FXint index) const { return (FXint)(FXival)artistlist->getItemData(index); }
2605
getAlbum(FXint index) const2606 FXint GMTrackView::getAlbum(FXint index) const {
2607 return albumlist->getItemId(index);
2608 }
2609
getTrack(FXint index) const2610 FXint GMTrackView::getTrack(FXint index) const { return (FXint)(FXival)tracklist->getItemId(index); }
2611