Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions build_installers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from virtualenv.run import cli_run as virtualenv
from xicam.gui.cammart.venvs import activate_this
from pip._internal import main as pip
import subprocess

if __name__ == '__main__':

# create clean build venv
virtualenv(['build-venv', '--clear', '--copies'])

# activate that venv
activate_this('build-venv')

# install xicam and its dependencies in the venv
pip(['install', '.'])

# Run NSIS to make an installer; check that its successful
assert not subprocess.call(['makensis', 'installer.nsi'])
137 changes: 137 additions & 0 deletions installer.nsi
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
; Note: This script must be located at a top-level above all xi-cam repos. You'll have to manually copy it one directory up.

; -------------------------------
; Start
!include MUI2.nsh
!include x64.nsh
!define VERSION "2.0.1"
!define MUI_PRODUCT "Xi-cam"
!define MUI_FILE "xicam"
!define MUI_BRANDINGTEXT "Xi-cam ${VERSION}"
CRCCheck On

; We should test if we must use an absolute path
;!include "${NSISDIR}\Contrib\Modern UI\System.nsh"


;---------------------------------
;General

Name "Xi-cam ${VERSION}"
OutFile "Xi-cam-${VERSION}-amd64.exe"
;ShowInstDetails "nevershow"
;ShowUninstDetails "nevershow"
;SetCompressor "bzip2"

!define MUI_INSTFILESPAGE_COLORS "FFFFFF 000000" ;Two colors
!define MUI_PAGE_HEADER_TEXT "Xi-cam ${Version} Installation:"
!define MUI_ICON "xicam\gui\static\icons\xicam.ico"
!define MUI_UNICON "xicam\gui\static\icons\xicam.ico"
;!define MUI_SPECIALBITMAP "Bitmap.bmp"


;--------------------------------
;Variables

Var StartMenuFolder


;--------------------------------
;Folder selection page

InstallDir "$PROGRAMFILES64\${MUI_PRODUCT}"


;--------------------------------
;Modern UI Configuration

!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "LICENSE.md"
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_STARTMENU "Application" $StartMenuFolder
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_UNPAGE_WELCOME
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_LICENSE "LICENSE.md"
!insertmacro MUI_UNPAGE_COMPONENTS
!insertmacro MUI_UNPAGE_DIRECTORY
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH
!insertmacro MUI_PAGE_FINISH

; !define MUI_COMPONENTSPAGE_SMALLDESC ;No value


;--------------------------------
;Language

!insertmacro MUI_LANGUAGE "English"


;--------------------------------
;Data

LicenseData "LICENSE.md"


;--------------------------------
;Installer Sections
Section "Install"

;Add files
SetOutPath "$INSTDIR"

File /r build-venv\*

;create desktop shortcut
CreateShortCut "$DESKTOP\${MUI_PRODUCT}.lnk" "$INSTDIR\Scripts\${MUI_FILE}.exe" "" "$INSTDIR\Lib\site-packages\${MUI_ICON}" 0

;create start-menu items
CreateDirectory "$SMPROGRAMS\${MUI_PRODUCT}"
CreateShortCut "$SMPROGRAMS\${MUI_PRODUCT}\Uninstall.lnk" "$INSTDIR\Uninstall.exe" "" "$INSTDIR\Lib\site-packages\${MUI_ICON}" 0
CreateShortCut "$SMPROGRAMS\${MUI_PRODUCT}\${MUI_PRODUCT}.lnk" "$INSTDIR\Scripts\${MUI_FILE}.exe" "" "$INSTDIR\Lib\site-packages\${MUI_ICON}" 0

;write uninstall information to the registry
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${MUI_PRODUCT}" "DisplayName" "${MUI_PRODUCT} (remove only)"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${MUI_PRODUCT}" "UninstallString" "$INSTDIR\Uninstall.exe"

WriteUninstaller "$INSTDIR\Uninstall.exe"

SectionEnd


;--------------------------------
;Uninstaller Section
Section "Uninstall"

;Delete Files
RMDir /r "$INSTDIR\*.*"

;Remove the installation directory
RMDir "$INSTDIR"

;Delete Start Menu Shortcuts
Delete "$DESKTOP\${MUI_PRODUCT}.lnk"
Delete "$SMPROGRAMS\${MUI_PRODUCT}\*.*"
RmDir "$SMPROGRAMS\${MUI_PRODUCT}"

;Delete Uninstaller And Unistall Registry Entries
DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\${MUI_PRODUCT}"
DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${MUI_PRODUCT}"

SectionEnd


;--------------------------------
;MessageBox Section


;Function that calls a messagebox when installation finished correctly
Function .onInstSuccess
MessageBox MB_OK "You have successfully installed ${MUI_PRODUCT}. Use the desktop icon to start the program."
FunctionEnd

Function un.onUninstSuccess
MessageBox MB_OK "You have successfully uninstalled ${MUI_PRODUCT}."
FunctionEnd

4 changes: 2 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ description-file = README.rst
VCS = git
style = pep440
versionfile_source = xicam/_version.py
versionfile_build =
tag_prefix =
versionfile_build = xicam/_version.py
tag_prefix = v

[flake8]
;ignore = E226,E302,E41
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@
# "scripts" keyword. Entry points provide cross-platform support and allow
# pip to create the appropriate form of executable for the target platform.
entry_points={
"gui_scripts": ["xicam=xicam.run_xicam:main"],
"gui_scripts": ["xicam=xicam.run_xicam:main",
"splash_xicam=xicam.gui.windows.splash:main"],
"xicam.plugins.DataHandlerPlugin": ["npy = xicam.core.formats.NPYPlugin:NPYPlugin"],
"xicam.plugins.PluginType": [
"CatalogPlugin = xicam.plugins.catalogplugin:CatalogPlugin",
Expand Down
Binary file modified xicam/gui/static/icons/xicam.ico
Binary file not shown.
Binary file added xicam/gui/static/images/animated-logo.mp4
Binary file not shown.
Binary file removed xicam/gui/static/images/animated_logo.gif
Binary file not shown.
4 changes: 3 additions & 1 deletion xicam/gui/windows/mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ def __init__(self):
super(XicamMainWindow, self).__init__()

# Set icon
self.setWindowIcon(QIcon(QPixmap(str(path("icons/xicam.gif")))))
xicam_icon = QIcon(QPixmap(str(path("icons/xicam.ico"))))
self.setWindowIcon(xicam_icon)
QApplication.instance().setWindowIcon(xicam_icon)

# Set size and position
self.setGeometry(0, 0, 1000, 600)
Expand Down
115 changes: 59 additions & 56 deletions xicam/gui/windows/splash.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import sys

from qtpy.QtCore import QTimer, Qt
from qtpy.QtGui import QMovie, QPixmap
from qtpy.QtWidgets import QSplashScreen, QApplication
from qtpy.QtWidgets import QWidget, QLabel, QSizePolicy
from qtpy.QtMultimedia import QMediaPlayer, QMediaPlaylist, QMediaContent
from qtpy.QtMultimediaWidgets import QVideoWidget
from qtpy.QtCore import QUrl
from qtpy.QtWidgets import QApplication, QVBoxLayout, QMainWindow

from xicam.gui import static

Expand All @@ -12,10 +16,10 @@ def elide(s: str, max_len: int = 60):
return s


class XicamSplashScreen(QSplashScreen):
class XicamSplashScreen(QMainWindow):
minsplashtime = 5000

def __init__(self, log_path: str, initial_length: int, f: int = Qt.WindowStaysOnTopHint | Qt.SplashScreen):
def __init__(self, log_path: str, initial_length: int):
"""
A QSplashScreen customized to display an animated gif. The splash triggers launch when clicked.

Expand All @@ -27,25 +31,42 @@ def __init__(self, log_path: str, initial_length: int, f: int = Qt.WindowStaysOn
Path to the Xi-CAM log file to reflect
initial_length: int
Length in bytes to seek forward before reading
f : int
Extra flags (see base class)
"""

# Get logo movie from relative path
self.movie = QMovie(str(static.path("images/animated_logo.gif")))
super(XicamSplashScreen, self).__init__(flags=Qt.WindowStaysOnTopHint | Qt.SplashScreen)

self.videoWidget = QVideoWidget()
self.videoWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
playlist = QMediaPlaylist(self.mediaPlayer)
playlist.setPlaybackMode(QMediaPlaylist.Loop)
playlist.addMedia(QMediaContent(QUrl.fromLocalFile(str(static.path("images/animated-logo.mp4")))))
playlist.setCurrentIndex(1)
self.mediaPlayer.setPlaylist(playlist)
self.mediaPlayer.setVideoOutput(self.videoWidget)
self.mediaPlayer.play()
self.mediaPlayer.mediaChanged.connect(self.execlaunch)


w = QWidget()
self.setCentralWidget(w)
self._layout = QVBoxLayout()
w.setLayout(self._layout)
w.layout().addWidget(self.videoWidget)
self.messageWidget = QLabel()
self.setStyleSheet('background-color:black; color:grey;')
w.layout().addWidget(self.messageWidget)
w.layout().setContentsMargins(10,30,10,10)
# w.layout().setSpacing(0)
self.setFixedSize(550, 400)

self.setWindowFlags(Qt.FramelessWindowHint)

# Setup drawing
self.movie.frameChanged.connect(self.paintFrame)
self.movie.jumpToFrame(1)
self.pixmap = QPixmap(self.movie.frameRect().size())
super(XicamSplashScreen, self).__init__(self.pixmap, f)
self.setMask(self.pixmap.mask())
self.movie.finished.connect(self.restartmovie)
self.showMessage("Starting Xi-CAM...")
self.messageWidget.setText("Starting Xi-CAM...")

self._launching = False
self._launchready = False
self.timer = QTimer(self)

self.log_file = open(log_path, "r")
self.log_file.seek(initial_length)
Expand All @@ -58,59 +79,36 @@ def __init__(self, log_path: str, initial_length: int, f: int = Qt.WindowStaysOn
QApplication.instance().setActiveWindow(self)

# Setup timed triggers for launching the QMainWindow
self.timer.singleShot(self.minsplashtime, self.launchwindow)
self.finish_timer = QTimer(self)
self.finish_timer.singleShot(self.minsplashtime, self.execlaunch)

self.message_timer = QTimer(self)
self.message_timer.timeout.connect(self.showMessageFromLog)
self.message_timer.start(1./60)

def showMessageFromLog(self):
line = self.log_file.readline().strip()
if line:
self.showMessage(elide(line.split(">")[-1]))

def showMessage(self, message: str, color=Qt.darkGray):
def showMessage(self, message: str):
# attempt to parse out everyting besides the message
try:
message=message.split(" - ")[-1]
except Exception:
pass
else:
super(XicamSplashScreen, self).showMessage(elide(message), color=color, alignment=Qt.AlignBottom)
self.messageWidget.setText(elide(message))

def mousePressEvent(self, *args, **kwargs):
# TODO: Apparently this doesn't work?
self.timer.stop()
self.finish_timer.stop()
self.execlaunch()

def show(self):
"""
Start the animation when shown
"""
super(XicamSplashScreen, self).show()
self.movie.start()

def paintFrame(self):
"""
Paint the current frame
"""
self.pixmap = self.movie.currentPixmap()
self.setMask(self.pixmap.mask())
self.setPixmap(self.pixmap)
self.movie.setSpeed(self.movie.speed() + 20)

line = self.log_file.readline().strip()
if line:
self.showMessage(elide(line.split(">")[-1]))

def sizeHint(self):
return self.movie.scaledSize()

def restartmovie(self):
"""
Once the animation reaches the end, check if its time to launch, otherwise restart animation
"""
if self._launchready:
self.execlaunch()
return
self.movie.start()

def launchwindow(self):
"""
Save state, defer launch until animation finishes
"""
self._launchready = True

def execlaunch(self):
"""
Expand All @@ -119,16 +117,21 @@ def execlaunch(self):
if not self._launching:
self._launching = True

self.timer.stop()
self.finish_timer.stop()

# Stop splashing
self.hide()
self.movie.stop()
self.close()
QApplication.instance().quit()


if __name__ == "__main__":
def main():
qapp = QApplication([])
splash = XicamSplashScreen(sys.argv[-2], int(sys.argv[-1]))
# splash = XicamSplashScreen('C:\\Users\LBL\\AppData\\Local\\CAMERA\\xicam\\Cache\\logs\\out.log', 1)
splash.show()
qapp.exec_()


if __name__ == "__main__":
main()
Loading