vision-0.0.5.0: src/Playlist/UI.hs
-- -*-haskell-*-
-- Vision (for the Voice): an XMMS2 client.
--
-- Author: Oleg Belozeorov
-- Created: 22 Jun. 2010
--
-- Copyright (C) 2010, 2011 Oleg Belozeorov
--
-- This program is free software; you can redistribute it and/or
-- modify it under the terms of the GNU General Public License as
-- published by the Free Software Foundation; either version 3 of
-- the License, or (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- General Public License for more details.
--
{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}
module Playlist.UI
( setupUI
) where
import Control.Monad
import Control.Monad.Trans
import Control.Monad.W
import Control.Monad.ToIO
import Control.Monad.EnvIO
import Control.Concurrent
import Control.Concurrent.STM
import Control.Concurrent.STM.TWatch
import Control.Concurrent.STM.TGVar
import Data.Env
import System.IO.Unsafe
import Network.URL
import Graphics.UI.Gtk hiding (add, remove)
import XMMS2.Client hiding (Data, playbackStatus)
import UI
import XMMS
import Playback
import Playtime
import Volume
import Utils
import Clipboard
import Location
import Collection
import Compound
import Editor
import Registry
import Properties hiding (showPropertyEditor, showPropertyExport)
import Playlist.Model
import Playlist.View
import Playlist.Edit
import Playlist.Config
import Playlist.Control
setupUI builder = do
setupWindowTitle
Just ptEnv <- getEnv playtimeEnv
Just volEnv <- getEnv volumeEnv
runIn (ptEnv :*: volEnv) $> setupPlaybar builder
Just env <- getEnv clipboardEnv
runIn (env :*: registryEnv) $> setupActions builder
liftIO $ do
playlistView `onRowActivated` \[n] _ ->
playTrack n
popup <- getWidget castToMenu "ui/playlist-popup"
setupTreeViewPopup playlistView popup
window `onDestroy` mainQuit
return ()
setupActions builder = do
urlEntryDialog <- liftIO $ unsafeInterleaveIO $ makeURLEntryDialog
orderDialog <- liftIO $ unsafeInterleaveIO $ makeOrderDialog $ \v -> do
let outerw = outer v
windowSetDefaultSize outerw 500 400
nw <- atomically $ newEmptyTWatch playlistName
tid <- forkIO $ forever $ do
name <- atomically $ watch nw
windowSetTitle outerw $
"Sort playlist" ++ maybe "" (": " ++) name
outerw `onDestroy` (killThread tid)
W runR <- runIn registryEnv
W runC <- runIn clipboardEnv
liftIO $ bindActions builder
[ ("play", startPlayback False)
, ("pause", pausePlayback)
, ("stop", stopPlayback)
, ("prev", prevTrack)
, ("next", nextTrack)
, ("quit", mainQuit)
, ("cut", runC $ editDelete True)
, ("copy", runC $ editCopy)
, ("paste", runC $ editPaste False)
, ("append", runC $ editPaste True)
, ("delete", runC $ editDelete False)
, ("select-all", editSelectAll)
, ("invert-selection", editInvertSelection)
, ("browse-location", browseLocation SortAscending Nothing)
, ("browse-collection", runR $ browseCollection Nothing)
, ("add-media", runURLEntryDialog urlEntryDialog)
, ("clear-playlist", clearPlaylist)
, ("sort-by", showOrderDialog orderDialog getOrder setOrder)
, ("configure-playlist", showPlaylistConfigDialog)
, ("edit-properties", showPropertyEditor)
, ("export-properties", showPropertyExport)
, ("import-properties", showPropertyImport)
, ("manage-properties", showPropertyManager)
]
setupServerActionGroup builder
setupPlaybackActions builder
setupTrackActions builder
setupSelectionActions builder
setupClipboardActions builder
return ()
setupServerActionGroup builder = liftIO $ do
ag <- builderGetObject builder castToActionGroup "server-actions"
cW <- atomically $ newTGWatch connectedV
forkIO $ forever $ do
c <- atomically $ watch cW
actionGroupSetSensitive ag c
setupPlaybackActions builder = liftIO $ do
play <- action builder "play"
pause <- action builder "pause"
stop <- action builder "stop"
psW <- atomically $ newEmptyTWatch playbackStatus
forkIO $ forever $ do
ps <- atomically $ watch psW
postGUISync $ do
let (ePlay, ePause, eStop) = case ps of
Just StatusPlay -> (False, True, True)
Just StatusPause -> (True, False, True)
_ -> (True, False, False)
actionSetSensitive play ePlay
actionSetVisible play ePlay
actionSetSensitive pause ePause
actionSetVisible pause ePause
actionSetSensitive stop eStop
setupTrackActions builder = liftIO $ do
prev <- action builder "prev"
next <- action builder "next"
ctW <- atomically $ newEmptyTWatch currentTrack
psW <- atomically $ newEmptyTWatch playlistSize
forkIO $ forever $ do
atomically $ (void $ watch ctW) `mplus` (void $ watch psW)
size <- getPlaylistSize
name <- getPlaylistName
cpos <- getCurrentTrack
let (ep, en) = case (name, cpos) of
(Just n, Just (ct, cn)) ->
(n == cn && ct > 0, n == cn && ct < size - 1)
_ ->
(False, False)
actionSetSensitive prev ep
actionSetSensitive next en
setupSelectionActions builder = liftIO $ do
acts <- mapM (action builder) ["cut", "copy", "delete", "edit-properties", "export-properties"]
playlistSel `onSelectionChanged` setup acts
postGUIAsync $ setup acts
where setup acts = do
n <- treeSelectionCountSelectedRows playlistSel
mapM_ (`actionSetSensitive` (n /= 0)) acts
setupClipboardActions builder =
runIn clipboardEnv $> do
ts <- clipboardTargets
io $ \run -> do
acts <- mapM (action builder) ["paste", "append"]
ctW <- atomically $ newEmptyTWatch ts
forkIO $ forever $ do
void $ atomically $ watch ctW
en <- run editCheckClipboard
mapM_ (`actionSetSensitive` en) acts
setupWindowTitle = liftIO $ do
pnW <- atomically $ newEmptyTWatch playlistName
forkIO $ forever $ do
name <- atomically $ watch pnW
setWindowTitle $ maybe "Vision playlist" (++ " - Vision playlist") name
setupPlaybar builder = do
seekView <- makeSeekControl
volView <- makeVolumeControl
liftIO $ do
playbar <- builderGetObject builder castToToolbar "playbar"
sep <- separatorToolItemNew
separatorToolItemSetDraw sep False
toolbarInsert playbar sep (-1)
seekItem <- toolItemNew
toolItemSetHomogeneous seekItem False
toolItemSetExpand seekItem True
containerAdd seekItem seekView
toolbarInsert playbar seekItem (-1)
sep <- separatorToolItemNew
separatorToolItemSetDraw sep False
toolbarInsert playbar sep (-1)
volumeItem <- toolItemNew
toolItemSetHomogeneous volumeItem False
toolItemSetExpand volumeItem False
widgetSetSizeRequest volumeItem 100 (-1)
containerAdd volumeItem volView
toolbarInsert playbar volumeItem (-1)
return ()
data URLEntry =
URLEntry { urlEntry :: Entry
, urlBox :: HBox
}
instance CompoundWidget URLEntry where
type Outer URLEntry = HBox
outer = urlBox
instance EditorWidget URLEntry where
type Data URLEntry = String
setData e = entrySetText (urlEntry e)
getData = entryGetText . urlEntry
clearData = flip setData ""
getState = const $ return (True, True)
resetModified = const $ return ()
focusView = widgetGrabFocus . urlEntry
makeURLEntry _ _ = do
box <- hBoxNew False 0
containerSetBorderWidth box 7
entry <- entryNew
entrySetActivatesDefault entry True
boxPackStartDefaults box entry
return URLEntry { urlEntry = entry
, urlBox = box
}
makeURLEntryDialog =
makeEditorDialog [] makeURLEntry $ \v -> do
let outerw = outer v
windowSetTitle outerw "Add media"
windowSetDefaultSize outerw 500 (-1)
runURLEntryDialog dlg =
runEditorDialog dlg (return "")
(\str ->
insertURIs (map (encString False ok_url) $ lines str) Nothing)
False window