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