summaryrefslogtreecommitdiff
path: root/src/Main.hs
blob: bc121e0366e9104495ebad197fd655edaad2f628 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
-- This file is part of Qtah.
--
-- Copyright 2015-2020 The Qtah Authors.
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
--
-- You should have received a copy of the GNU Lesser General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.

{-# LANGUAGE ScopedTypeVariables #-}

module Main where

import Control.Arrow ((&&&))
import Control.Monad (forM_)
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import qualified Data.Map as M
import Foreign.Hoppy.Runtime (withScopedPtr)
import qualified Graphics.UI.Qtah.Core.QCoreApplication as QCoreApplication
import qualified Graphics.UI.Qtah.Core.QItemSelectionModel as QItemSelectionModel
import qualified Graphics.UI.Qtah.Core.QModelIndex as QModelIndex
import qualified Graphics.UI.Qtah.Core.QStringListModel as QStringListModel
import qualified Graphics.UI.Qtah.Core.QVariant as QVariant
import Graphics.UI.Qtah.Event (onEvent)
import qualified Graphics.UI.Qtah.Example.Notepad as Notepad
import qualified Graphics.UI.Qtah.Gui.QCloseEvent as QCloseEvent
import qualified Graphics.UI.Qtah.Gui.QFont as QFont
import qualified Graphics.UI.Qtah.Widgets.QAbstractButton as QAbstractButton
import qualified Graphics.UI.Qtah.Widgets.QAbstractItemView as QAbstractItemView
import qualified Graphics.UI.Qtah.Widgets.QApplication as QApplication
import qualified Graphics.UI.Qtah.Widgets.QBoxLayout as QBoxLayout
import qualified Graphics.UI.Qtah.Widgets.QLabel as QLabel
import qualified Graphics.UI.Qtah.Widgets.QListView as QListView
import qualified Graphics.UI.Qtah.Widgets.QPushButton as QPushButton
import qualified Graphics.UI.Qtah.Widgets.QSplitter as QSplitter
import qualified Graphics.UI.Qtah.Widgets.QVBoxLayout as QVBoxLayout
import qualified Graphics.UI.Qtah.Widgets.QWidget as QWidget
import Graphics.UI.Qtah.Signal (connect_)
import System.Environment (getArgs)

data Example = Example
  { exTitle :: String
  , exDescription :: String
  , exMain :: IO ()
  }

examples :: [Example]
examples =
  [ Example
    { exTitle = "Notepad"
    , exDescription = "A notepad program for editing text files."
    , exMain = Notepad.run
    }
  ]

examplesByTitle :: M.Map String Example
examplesByTitle = M.fromList $ map (exTitle &&& id) examples

-- | State of the example chooser UI.
data UI = UI
  { uiWindow :: QWidget.QWidget
  , uiListModel :: QStringListModel.QStringListModel
  , uiCurrentExampleRef :: IORef (Maybe Example)
  , uiDescriptionLabel :: QLabel.QLabel
  }

main :: IO ()
main = withScopedPtr (getArgs >>= QApplication.new) $ \_ -> do
  ui <- newChooserWindow
  QWidget.show $ uiWindow ui
  QCoreApplication.exec

newChooserWindow :: IO UI
newChooserWindow = do
  -- Create and initialize widgets.

  window <- QWidget.new
  QWidget.setWindowTitle window "Qtah Examples"
  QWidget.resizeRaw window 500 350

  model <- QStringListModel.newWithContents $ M.keys examplesByTitle
  listView <- QListView.new
  QAbstractItemView.setModel listView model
  QAbstractItemView.setEditTriggers listView QAbstractItemView.noEditTriggers

  titleLabel <- QLabel.newWithText "Qtah Example Programs"
  titleFont <- QWidget.font titleLabel
  QFont.setPixelSize titleFont 25
  QWidget.setFont titleLabel titleFont

  descriptionLabel <- QLabel.new
  QLabel.setWordWrap descriptionLabel True

  runButton <- QPushButton.newWithText "&Launch"

  quitButton <- QPushButton.newWithText "&Quit"

  rightBox <- QWidget.new
  rightBoxLayout <- QVBoxLayout.new
  QWidget.setLayout rightBox rightBoxLayout
  QBoxLayout.addWidget rightBoxLayout descriptionLabel
  QBoxLayout.addStretch rightBoxLayout
  QBoxLayout.addWidget rightBoxLayout runButton
  QBoxLayout.addWidget rightBoxLayout quitButton

  splitter <- QSplitter.new
  QSplitter.addWidget splitter listView
  QSplitter.addWidget splitter rightBox
  QSplitter.setSizes splitter [200 :: Int, 300]

  layout <- QVBoxLayout.newWithParent window
  QBoxLayout.addWidget layout titleLabel
  QBoxLayout.addWidgetWithStretch layout splitter 1

  -- Set up signals.

  currentExampleRef <- newIORef Nothing

  let ui = UI { uiWindow = window
              , uiListModel = model
              , uiCurrentExampleRef = currentExampleRef
              , uiDescriptionLabel = descriptionLabel
              }

  _ <- onEvent window $ \(_ :: QCloseEvent.QCloseEvent) -> do
    QCoreApplication.quit
    return False

  selectionModel <- QAbstractItemView.selectionModel listView
  connect_ selectionModel QItemSelectionModel.currentChangedSignal $ \index _ ->
    exampleSelected ui index

  connect_ listView QAbstractItemView.doubleClickedSignal $ \_ -> runSelectedExample ui

  connect_ runButton QAbstractButton.clickedSignal $ \_ -> runSelectedExample ui

  connect_ quitButton QAbstractButton.clickedSignal $ \_ -> QCoreApplication.quit

  return ui

exampleSelected :: UI -> QModelIndex.QModelIndex -> IO ()
exampleSelected ui index = do
  name <- QVariant.toString =<< QModelIndex.getData index
  -- If we can't find the example, then do nothing.
  forM_ (M.lookup name examplesByTitle) $ \example -> do
    writeIORef (uiCurrentExampleRef ui) $ Just example
    QLabel.setText (uiDescriptionLabel ui) $ exDescription example

runSelectedExample :: UI -> IO ()
runSelectedExample ui = do
  maybeExample <- readIORef $ uiCurrentExampleRef ui
  forM_ maybeExample $ \example -> exMain example