1 /*******************************************************************************
2 *                         Goggles Music Manager                                *
3 ********************************************************************************
4 *           Copyright (C) 2006-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 "icons.h"
20 #include "gmdefs.h"
21 #include <FXPNGIcon.h>
22 #include <FXPNGImage.h>
23 #include "GMTrack.h"
24 #include "GMList.h"
25 #include "GMSource.h"
26 #include "GMPlayerManager.h"
27 #include "GMCover.h"
28 #include "GMCoverManager.h"
29 #include "GMWindow.h"
30 #include "GMRemote.h"
31 #include "GMIconTheme.h"
32 
33 // Map
34 FXDEFMAP(GMRemote) GMRemoteMap[]={
35   FXMAPFUNC(SEL_COMMAND,						GMRemote::ID_VOLUME_SLIDER,			GMRemote::onCmdVolume),
36   FXMAPFUNC(SEL_CHANGED,						GMRemote::ID_VOLUME_SLIDER,			GMRemote::onCmdVolume),
37   FXMAPFUNC(SEL_MOUSEWHEEL,					GMRemote::ID_VOLUME_BUTTON,     GMRemote::onCmdVolumeButton),
38   FXMAPFUNC(SEL_MOUSEWHEEL,					0,															GMRemote::onCmdVolumeButton),
39   FXMAPFUNC(SEL_COMMAND,        		GMRemote::ID_TIMESLIDER,        GMRemote::onCmdTimeSlider),
40   FXMAPFUNC(SEL_LEFTBUTTONPRESS, 		GMRemote::ID_TIME_LABEL,        GMRemote::onCmdSetTimeLabelDirection),
41   FXMAPFUNC(SEL_RIGHTBUTTONPRESS, 	GMRemote::ID_TIME_LABEL,        GMRemote::onCmdSetTimeLabelDirection),
42   };
43 
44 // Implementation
FXIMPLEMENT(GMRemote,FXMainWindow,GMRemoteMap,ARRAYNUMBER (GMRemoteMap))45 FXIMPLEMENT(GMRemote,FXMainWindow,GMRemoteMap,ARRAYNUMBER(GMRemoteMap))
46 
47 GMRemote::GMRemote(FXApp* a,FXObject * tgt,FXSelector msg):FXMainWindow(a,"Goggles Music Manager",nullptr,nullptr,DECOR_BORDER|DECOR_TITLE|DECOR_CLOSE|DECOR_STRETCHABLE,0,0,0,0,3,3,3,3,3,3){
48   flags|=FLAG_ENABLED;
49   cover=nullptr;
50 
51   setTarget(tgt);
52   setSelector(msg);
53 
54   setIcon(GMIconTheme::instance()->icon_applogo);
55   setMiniIcon(GMIconTheme::instance()->icon_applogo_small);
56 
57   FXFontDesc fontdescription = getApp()->getNormalFont()->getFontDesc();
58   fontdescription.weight = FXFont::Bold;
59   fontdescription.size  += 10;
60   font_title = new FXFont(getApp(),fontdescription);
61   font_title->create();
62 
63   coversize = getApp()->reg().readUIntEntry("window","remote-cover-size",coversize);
64 
65   img_default = new FXPNGImage(getApp(),about_png);
66   img_default->scale(coversize,coversize,FOX_SCALE_BEST);
67   img_default->blend(getApp()->getBackColor());
68   img_default->create();
69 
70   cover_label = new FXImageFrame(this,img_default,LAYOUT_SIDE_LEFT|FRAME_SUNKEN|LAYOUT_FIX_WIDTH|JUSTIFY_CENTER_X|JUSTIFY_CENTER_Y|LAYOUT_FILL_Y,0,0,coversize,coversize);
71   cover_label->setBackColor(getApp()->getBackColor());
72 
73   /// Popup Volume Menu
74   volumecontrol = new FXPopup(this,POPUP_VERTICAL|FRAME_RAISED|FRAME_THICK|POPUP_SHRINKWRAP);
75   volumeslider = new FXSlider(volumecontrol,this,GMRemote::ID_VOLUME_SLIDER,LAYOUT_FIX_HEIGHT|LAYOUT_FIX_WIDTH|SLIDER_VERTICAL|SLIDER_TICKS_RIGHT|SLIDER_TICKS_LEFT|SLIDER_INSIDE_BAR,0,0,20,100);
76   volumeslider->setTickDelta(10);
77   volumeslider->setRange(0,100);
78   volumeslider->setIncrement(10);
79 
80   FXHorizontalFrame * buttons = new FXHorizontalFrame(this,LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X,0,0,0,0,3,3,0,0);
81   new FXButton(buttons,tr("\tShow Browser\tShow Browser"),GMIconTheme::instance()->icon_home,GMPlayerManager::instance()->getMainWindow(),GMWindow::ID_SHOW_BROWSER,BUTTON_TOOLBAR|FRAME_RAISED|ICON_ABOVE_TEXT);
82   new FXVerticalSeparator(buttons,LAYOUT_FILL_Y|SEPARATOR_GROOVE);
83   new FXButton(buttons,tr("\tStart Playback\tStart Playback"),GMIconTheme::instance()->icon_play,GMPlayerManager::instance()->getMainWindow(),GMWindow::ID_PLAYPAUSEMENU,BUTTON_TOOLBAR|FRAME_RAISED|ICON_ABOVE_TEXT);
84   new FXButton(buttons,tr("\tStop Playback\tStop Playback"),GMIconTheme::instance()->icon_stop,GMPlayerManager::instance()->getMainWindow(),GMWindow::ID_STOP,BUTTON_TOOLBAR|FRAME_RAISED|ICON_ABOVE_TEXT);
85   new FXVerticalSeparator(buttons,LAYOUT_FILL_Y|SEPARATOR_GROOVE);
86   new FXButton(buttons,tr("\tPlay Previous Track\tPlay previous track."),GMIconTheme::instance()->icon_prev,GMPlayerManager::instance()->getMainWindow(),GMWindow::ID_PREV,BUTTON_TOOLBAR|FRAME_RAISED|ICON_ABOVE_TEXT);
87   new FXButton(buttons,tr("\tPlay Next Track\tPlay next track."),GMIconTheme::instance()->icon_next,GMPlayerManager::instance()->getMainWindow(),GMWindow::ID_NEXT,BUTTON_TOOLBAR|FRAME_RAISED|ICON_ABOVE_TEXT);
88   new FXVerticalSeparator(buttons,LAYOUT_FILL_Y|SEPARATOR_GROOVE);
89   time_label =new FX7Segment(buttons,"--:--",SEVENSEGMENT_SHADOW|LAYOUT_CENTER_Y);
90   time_label->setCellWidth(10);
91   time_label->setCellHeight(15);
92   time_label->setTarget(this);
93   time_label->setSelector(ID_TIME_LABEL);
94   new FXVerticalSeparator(buttons,LAYOUT_FILL_Y|SEPARATOR_GROOVE);
95   volumebutton = new FXMenuButton(buttons,tr("\tAdjust Volume\tAdjust Volume"),nullptr,volumecontrol,MENUBUTTON_NOARROWS|MENUBUTTON_ATTACH_LEFT|MENUBUTTON_UP|MENUBUTTON_TOOLBAR|FRAME_RAISED|LAYOUT_CENTER_Y);
96   volumebutton->setTarget(this);
97   volumebutton->setSelector(ID_VOLUME_BUTTON);
98 
99   FXVerticalFrame * info = new FXVerticalFrame(this,LAYOUT_CENTER_Y|FRAME_NONE|LAYOUT_FILL_X,0,0,0,0,2,2,2,2,0,0);
100   title_label = new FXTextField(info,20,nullptr,0,FRAME_NONE|TEXTFIELD_READONLY,0,0,0,0,0,0,0,0);
101   title_label->setBackColor(getApp()->getBaseColor());
102   title_label->setFont(font_title);
103   title_label->setDefaultCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
104   title_label->setDragCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
105   title_label->disable();
106 
107   artistalbum_label = new FXTextField(info,30,nullptr,0,FRAME_NONE|TEXTFIELD_READONLY,0,0,0,0,0,0,0,0);
108   artistalbum_label->setBackColor(getApp()->getBaseColor());
109   artistalbum_label->setDefaultCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
110 
111   trackslider = new GMTrackProgressBar(info,this,ID_TIMESLIDER,LAYOUT_FILL_X|LAYOUT_CENTER_Y|FRAME_RAISED,0,0,0,0,0,0,0,0);
112   trackslider->setTotal(100000);
113   trackslider->setDefaultCursor(GMIconTheme::instance()->cursor_hand);
114   trackslider->setDragCursor(GMIconTheme::instance()->cursor_hand);
115 
116   getAccelTable()->addAccel("F11",GMPlayerManager::instance()->getMainWindow(),FXSEL(SEL_COMMAND,GMWindow::ID_SHOW_BROWSER));
117   getAccelTable()->addAccel("Ctrl-M",GMPlayerManager::instance()->getMainWindow(),FXSEL(SEL_COMMAND,GMWindow::ID_SHOW_BROWSER));
118   getAccelTable()->addAccel("Ctrl-W",this,FXSEL(SEL_CLOSE,0));
119   getAccelTable()->addAccel("Ctrl-Q",GMPlayerManager::instance()->getMainWindow(),FXSEL(SEL_COMMAND,GMWindow::ID_QUIT));
120 
121   getAccelTable()->addAccel("Ctrl-P",GMPlayerManager::instance()->getMainWindow(),FXSEL(SEL_COMMAND,GMWindow::ID_PLAYPAUSEMENU));
122   getAccelTable()->addAccel("Ctrl-\\",GMPlayerManager::instance()->getMainWindow(),FXSEL(SEL_COMMAND,GMWindow::ID_STOP));
123   getAccelTable()->addAccel("Ctrl-[",GMPlayerManager::instance()->getMainWindow(),FXSEL(SEL_COMMAND,GMWindow::ID_PREV));
124   getAccelTable()->addAccel("Ctrl-]",GMPlayerManager::instance()->getMainWindow(),FXSEL(SEL_COMMAND,GMWindow::ID_NEXT));
125 
126   reset();
127   }
128 
129 // Destroy main window
~GMRemote()130 GMRemote::~GMRemote(){
131   volumeslider->setTarget(nullptr);
132   volumeslider->setSelector(0);
133   volumebutton->setMenu(nullptr);
134 
135   if (cover) {
136     delete cover;
137     cover=nullptr;
138     }
139   updateCover();
140   }
141 
writeRegistry()142 void GMRemote::writeRegistry(){
143   if (shown()) {
144     getApp()->reg().writeIntEntry("window","remote-x",getX());
145     getApp()->reg().writeIntEntry("window","remote-y",getY());
146     getApp()->reg().writeIntEntry("window","remote-width",getWidth());
147     getApp()->reg().writeIntEntry("window","remote-height",getHeight());
148     getApp()->reg().writeBoolEntry("window","remote-time-remaining",is_remaining);
149     }
150   }
151 
updateCover()152 void GMRemote::updateCover() {
153   if (cover==nullptr) {
154     cover_label->setImage(img_default);
155     }
156   else {
157     cover->create();
158     cover_label->setImage(cover);
159     }
160   }
161 
162 
display(const GMTrack & track)163 void GMRemote::display(const GMTrack & track){
164   FXString tip = FXString::value("%s\n%s\n%s (%d)",track.title.text(),track.artist.text(),track.album.text(),track.year);
165 
166   title_label->setText(track.title);
167   title_label->setJustify(JUSTIFY_LEFT);
168   title_label->setCursorPos(0);
169   title_label->setAnchorPos(0);
170   title_label->makePositionVisible(0);
171   title_label->setTipText(tip);
172 
173   artistalbum_label->setText("by " + track.artist + " from " + track.album);
174   artistalbum_label->show();
175   artistalbum_label->setCursorPos(0);
176   artistalbum_label->setAnchorPos(0);
177   artistalbum_label->makePositionVisible(0);
178   artistalbum_label->setTipText(tip);
179   recalc();
180   }
181 
reset()182 void GMRemote::reset(){
183   title_label->setText("Goggles Music Manager");
184   title_label->setJustify(JUSTIFY_CENTER_X);
185   title_label->setLayoutHints(LAYOUT_CENTER_Y|LAYOUT_FILL_X);
186   title_label->setTipText(FXString::null);
187   artistalbum_label->setText(FXString::null);
188   artistalbum_label->setTipText(FXString::null);
189   artistalbum_label->hide();
190   time_label->setText("--:--");
191 
192   trackslider->disable();
193   trackslider->setProgress(0);
194 
195   if (cover) {
196     delete cover;
197     cover=nullptr;
198     }
199   updateCover();
200 
201   recalc();
202   layout();
203   }
204 
update_time(const TrackTime & c,const TrackTime & r,FXint progress,FXbool playing,FXbool seekable)205 void GMRemote::update_time(const TrackTime & c,const TrackTime & r,FXint progress,FXbool playing,FXbool seekable){
206   if (playing) {
207     if (is_remaining == false) {
208       if (c.hours>0)
209         time_label->setText(FXString::value("%d:%.2d:%.2d",c.hours,c.minutes,c.seconds));
210       else
211         time_label->setText(FXString::value("%.2d:%.2d",c.minutes,c.seconds));
212       }
213     else {
214       if (c.hours>0)
215         time_label->setText(FXString::value("-%d:%.2d:%.2d",r.hours,r.minutes,r.seconds));
216       else
217         time_label->setText(FXString::value("-%.2d:%.2d",r.minutes,r.seconds));
218       }
219     if (seekable) {
220       if (!trackslider->grabbed()){
221         trackslider->setProgress(progress);
222         }
223       trackslider->enable();
224       }
225     else {
226       trackslider->disable();
227       }
228     }
229   else {
230     time_label->setText("--:--");
231     trackslider->disable();
232     trackslider->setProgress(0);
233     }
234   }
235 
update_volume_display(FXint level)236 void GMRemote::update_volume_display(FXint level) {
237   if (level<0) {
238     volumebutton->setIcon(GMIconTheme::instance()->icon_volume_muted);
239     volumebutton->disable();
240     }
241   else {
242     if (level<=0)
243       volumebutton->setIcon(GMIconTheme::instance()->icon_volume_muted);
244     else if (level<=33)
245       volumebutton->setIcon(GMIconTheme::instance()->icon_volume_low);
246     else if (level<=66)
247       volumebutton->setIcon(GMIconTheme::instance()->icon_volume_medium);
248     else
249       volumebutton->setIcon(GMIconTheme::instance()->icon_volume_high);
250 
251     volumebutton->enable();
252     }
253 
254   if (!volumeslider->grabbed())
255     volumeslider->setValue(level);
256   }
257 
update_cover_display()258 void GMRemote::update_cover_display() {
259   if (cover) {
260     delete cover;
261     cover=nullptr;
262     }
263   cover = GMCover::copyToImage(GMPlayerManager::instance()->getCoverManager()->getCover(),coversize);
264   updateCover();
265   }
266 
267 
268 // Create and show window
create()269 void GMRemote::create(){
270   FXMainWindow::create();
271 
272   if (getApp()->reg().readIntEntry("window","remote-x",-1)!=-1) {
273     FXint xx=getApp()->reg().readIntEntry("window","remote-x",getX());
274     FXint yy=getApp()->reg().readIntEntry("window","remote-y",getY());
275     if (getApp()->reg().readIntEntry("window","remote-width",-1)!=-1) {
276       FXint ww=getApp()->reg().readIntEntry("window","remote-width",getDefaultWidth());
277       FXint hh=getApp()->reg().readIntEntry("window","remote-height",getDefaultHeight());
278       position(xx,yy,ww,hh);
279       }
280     else {
281       move(xx,yy);
282       }
283     }
284   else {
285     place(PLACEMENT_SCREEN);
286     }
287   is_remaining = getApp()->reg().readBoolEntry("window","remote-time-remaining",false);
288   gm_set_application_icon(this);
289   }
290 
doesOverrideRedirect() const291 bool GMRemote::doesOverrideRedirect() const { return false; }
292 
293 
onCmdVolume(FXObject *,FXSelector,void * ptr)294 long GMRemote::onCmdVolume(FXObject*,FXSelector,void*ptr){
295   FXint level = (FXint)(FXival)ptr;
296   GMPlayerManager::instance()->volume(level);
297   GMPlayerManager::instance()->getMainWindow()->update_volume_display(level);
298   update_volume_display(level);
299   return 1;
300   }
301 
onCmdVolumeButton(FXObject *,FXSelector sel,void * ptr)302 long GMRemote::onCmdVolumeButton(FXObject*,FXSelector sel,void*ptr){
303   volumeslider->handle(this,FXSEL(FXSELTYPE(sel),0),ptr);
304   return 1;
305   }
306 
onCmdTimeSlider(FXObject *,FXSelector,void * ptr)307 long GMRemote::onCmdTimeSlider(FXObject*,FXSelector,void*ptr){
308   FXdouble pos = *(FXdouble*)ptr;
309   GMPlayerManager::instance()->seek(pos);
310   return 1;
311   }
312 
onCmdSetTimeLabelDirection(FXObject *,FXSelector,void *)313 long GMRemote::onCmdSetTimeLabelDirection(FXObject*,FXSelector,void*){
314   is_remaining = !is_remaining;
315   return 1;
316 }
317