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