-- This file is part of Qtah.
--
-- Copyright 2015-2021 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 .
module Graphics.UI.Qtah.Generator.ListenerGen (
generateListenerCpp,
) where
import Data.List (intercalate)
import Graphics.UI.Qtah.Generator.Common (writeFileIfDifferent)
import Graphics.UI.Qtah.Generator.Config (Version)
import Graphics.UI.Qtah.Generator.Interface.Internal.Listener (ListenerDef (..), listeners)
import System.FilePath ((>))
generateListenerCpp :: FilePath -> IO ()
generateListenerCpp cppDirPath = do
writeFileIfDifferent (cppDirPath > "listener.hpp") hppSource
writeFileIfDifferent (cppDirPath > "listener.cpp") cppSource
-- TODO Generate this from the listener definitions themselves.
cppIncludes :: [String]
cppIncludes =
[ "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#include "
, "#if QT_VERSION >= 0x050000"
, "#include "
, "#endif"
, "#include \"b_callback.hpp\""
]
hppSource :: String
hppSource = (++ "\n") $ intercalate "\n" $
[ "////////// GENERATED FILE, EDITS WILL BE LOST //////////"
, ""
, "#ifndef QTAH_LISTENERS_HPP"
, "#define QTAH_LISTENERS_HPP"
, ""
] ++ cppIncludes ++
flip concatMap listeners (\l ->
let cn = listenerClassName l
ccn = listenerCallbackClassName l
pl = listenerCppParamList l
in [ "" ] ++
maybe [] (\v -> ["#if QT_VERSION >= " ++ renderVersionCppHex v, ""]) (listenerMinVersion l) ++
[ "class " ++ cn ++ " : public QObject {"
, " Q_OBJECT"
, ""
, "public:"
, " typedef " ++ ccn ++ " callback;"
, ""
, " " ++ cn ++ "(QObject* source, const std::string& signal, callback f);"
, " ~" ++ cn ++ "();"
, " bool isValid() const;"
, ""
, "public slots:"
, " void invoke(" ++ pl ++ ");"
, ""
, "private:"
, " callback f_;"
, " QMetaObject::Connection connection_;"
, "};"
] ++
maybe [] (\_ -> ["", "#endif"]) (listenerMinVersion l)
) ++
[ ""
, "#endif"
]
cppSource :: String
cppSource = (++ "\n") $ intercalate "\n" $
[ "////////// GENERATED FILE, EDITS WILL BE LOST //////////"
, ""
, "#include \"listener.hpp\""
, ""
, "#include "
] ++
flip concatMap listeners (\l ->
let cn = listenerClassName l
pl = listenerCppParamList l
ptl = listenerCppParamTypeList l
pnl = listenerCppParamNameList l
in [ "" ] ++
maybe [] (\v -> ["#if QT_VERSION >= " ++ renderVersionCppHex v, ""]) (listenerMinVersion l) ++
[ cn ++ "::" ++ cn ++ "(QObject* source, const std::string& signal, " ++ cn ++ "::callback f) :"
, " QObject(source), f_(f) {"
, " connection_ = connect(source, signal.c_str(), this, SLOT(invoke(" ++ ptl ++ ")));"
, "}"
, ""
, cn ++ "::~" ++ cn ++ "() {"
, " QObject::disconnect(connection_);"
, "}"
, ""
, "bool " ++ cn ++ "::isValid() const {"
, " return static_cast(connection_);"
, "}"
, ""
, "void " ++ cn ++ "::invoke(" ++ pl ++ ") {"
, " f_(" ++ pnl ++ ");"
, "}"
] ++
maybe [] (\_ -> ["", "#endif"]) (listenerMinVersion l)
)
renderVersionCppHex :: Version -> String
renderVersionCppHex version = "0x" ++ a' ++ b' ++ c'
where [a, b, c] = take 3 $ version ++ repeat 0
a' = pad a
b' = pad b
c' = pad c
pad n =
if 0 <= n && n < 10
then '0' : show n
else if 10 <= n && n < 100
then show n
else error $ "renderVersionCppHex expects 0 <= n < 100, n is " ++ show n ++ "."