diff --git a/src/pixctrl.nim b/src/pixctrl.nim index 2f88d13..ce65321 100644 --- a/src/pixctrl.nim +++ b/src/pixctrl.nim @@ -37,7 +37,7 @@ proc setTimeout*(seconds: string) = when isMainModule: var p = newParser("pixctrl"): help("Control utilitiy for randopix") - option("-s", "--server", help="Host running the randopix server", default="http://localhost/") + option("-s", "--server", help="Host running the randopix server", default="http://localhost:8080/") run: randopixServer = opts.server diff --git a/src/providers.nim b/src/providers.nim index 97c0575..1d8c977 100644 --- a/src/providers.nim +++ b/src/providers.nim @@ -1,4 +1,4 @@ -import os, sets, random, httpClient, json, strformat, options +import os, sets, random, httpClient, json, strformat, options, deques import gintro/[gdkpixbuf, gobject] import common @@ -6,7 +6,6 @@ const supportedExts = @[".png", ".jpg", ".jpeg"] foxesUrl = "https://randomfox.ca/floof/" inspiroUrl = "http://inspirobot.me/api?generate=true" - tmpFile = "/tmp/randopix_tmp.png" type FileOpResult* = object of OpResult @@ -18,17 +17,18 @@ type mode* : Mode ## Selects the API that is used to get images path*: Option[string] ## Path on the local file syetem that will be used in `file` mode exts: HashSet[string] ## Allowed extensions that the `file` mode will display - files: seq[string] ## Currently loaded list of images in `file` mode var client = newHttpClient() ## For loading images from the web + tmpDir = getTempDir() / "randopix" + tmpFile = tmpDir / "tmp.png" + fileList = initDeque[string]() ######################## # Constructors ######################## proc newImageProvider(verbose: bool, mode: Mode, path: Option[string]): ImageProvider = - randomize() ImageProvider(verbose: verbose, mode: mode, path: path, exts: supportedExts.toHashSet) proc newImageProvider*(verbose: bool): ImageProvider = @@ -94,20 +94,24 @@ proc getLocalFile(ip: var ImageProvider): FileOpResult = # First, check if there are still images left to be loaded. # If not reread all files from the path - if ip.files.len < 1: - if ip.path.isNone: - return newFileOpResultError("No path for image loading") - ip.log "Reloading file list..." + if fileList.len == 0: + var tmp: seq[string] + var split: tuple[dir, name, ext: string] for file in walkDirRec(ip.path.get): - let split = splitFile(file) + split = splitFile(file) if ip.exts.contains(split.ext): - ip.files.add(file) - ip.log fmt"Loaded {ip.files.len} files" - shuffle(ip.files) + tmp.add($file) + ip.log fmt"Loaded {tmp.len} files" + shuffle(tmp) + for file in tmp: + fileList.addLast(file) + if fileList.len == 0: + return newFileOpResultError("No files found") + + let next = fileList.popFirst() # Remove the current file after - result = newFileOpResult(ip.files[0]) - ip.files.delete(0) + result = newFileOpResult(next) proc getFileName(ip: var ImageProvider): FileOpResult = ## Get the temporary file name of the next file to display @@ -151,7 +155,10 @@ proc next*(ip: var ImageProvider, width, height: int): FileOpResult = return newFileOpResultError("Error while saving temporary image") # GTK pixbuf leaks memory when not manually decreasing reference count - pixbuf.genericGObjectUnref() - rawPixbuf.genericGObjectUnref() + pixbuf.unref() + rawPixbuf.unref() - newFileOpResult(tmpFile) \ No newline at end of file + newFileOpResult(tmpFile) + +createDir(tmpDir) +randomize() \ No newline at end of file diff --git a/src/randopix.nim b/src/randopix.nim index 2999c78..cf4afe7 100644 --- a/src/randopix.nim +++ b/src/randopix.nim @@ -28,6 +28,7 @@ var # Widgets window: ApplicationWindow label: Label + box: Box # Server vor recieving commands from external tools serverWorker: system.Thread[ServerArgs] @@ -35,14 +36,14 @@ proc log(things: varargs[string, `$`]) = if args.verbose: echo things.join() -proc notify(label: Label, message: string = "") = +proc notify(label: Label, things: varargs[string, `$`]) = ## Shows the notification box in the lower left corner. ## If no message is passed, the box will be hidden - label.text = message - if (message == ""): - label.hide + label.text = things.join() + if (label.text == ""): + box.hide else: - label.show + box.show proc newArgs(): Option[Args] = let p = newParser("randopix"): @@ -50,7 +51,7 @@ proc newArgs(): Option[Args] = option("-m", "--mode", help="The image source mode.", choices=enumToStrings(Mode)) option("-d", "--directoy", help="Path to a directory with images for the 'file' mode") option("-t", "--timeout", help="Seconds before the image is refreshed", default="300") - option("-p", "--port", help="Port over which the control server should be accessible", default="80") + option("-p", "--port", help="Port over which the control server should be accessible", default="8080") flag("-w", "--windowed", help="Do not start in fullscreen mode") flag("-v", "--verbose", help="Show more information") @@ -115,7 +116,7 @@ proc updateImage(image: Image): bool = e = getCurrentException() msg = getCurrentExceptionMsg() log "Got exception ", repr(e), " with message ", msg - label.notify "Error while refreshing image, retrying..." + label.notify "Error while refreshing, retrying..." return false proc timedUpdate(image: Image): bool = @@ -124,8 +125,8 @@ proc timedUpdate(image: Image): bool = return false proc forceUpdate(action: SimpleAction; parameter: Variant; image: Image): void = - log "Refreshing image..." - label.notify "Refreshing image..." + log "Refreshing..." + label.notify "Refreshing..." if updateTimeout > 0: discard updateTimeout.remove updateTimeout = int(timeoutAdd(500, timedUpdate, image)) @@ -152,8 +153,10 @@ proc checkServerChannel(image: Image): bool = of cMode: try: let mode = parseEnum[Mode](msg.parameter) - log "Switching mode: ", mode imageProvider.mode = mode + forceUpdate(nil, nil, image) + log "Switching mode: ", mode + label.notify fmt"Switch Mode: {msg.parameter.capitalizeAscii()}" except ValueError: log "Invalid mode: ", msg.parameter @@ -171,11 +174,11 @@ proc toggleFullscreen(action: SimpleAction; parameter: Variant; window: Applicat window.fullscreen args.fullscreen = not args.fullscreen -proc toggleHelp(action: SimpleAction; parameter: Variant; label: Label) = - if label.visible: - label.hide +proc toggleHelp(action: SimpleAction; parameter: Variant; box: Box) = + if box.visible: + box.hide else: - label.show + box.show proc cleanUp(w: ApplicationWindow, app: Application) = ## Stop the control server and exit the GTK application @@ -207,16 +210,25 @@ proc appActivate(app: Application) = # Create all windgets we are gonna use label = newLabel(fmt"Starting ('H' for help)...") - label.halign = Align.`end` - label.valign = Align.`end` + + let spinner = newSpinner() + spinner.start() + + box = newBox(Orientation.horizontal, 2) + box.halign = Align.`end` + box.valign = Align.`end` + box.packStart(spinner, true, true, 10) + box.packStart(label, true, true, 0) let helpText = newLabel(helpString) - helpText.halign = Align.start - helpText.valign = Align.start + let helpBox = newBox(Orientation.vertical, 0) + helpBox.packStart(helpText, true, true, 0) + helpBox.halign = Align.start + helpBox.valign = Align.start let container = newOverlay() - container.addOverlay(label) - container.addOverlay(helpText) + container.addOverlay(box) + container.addOverlay(helpBox) window.add(container) let image = newImage() @@ -244,7 +256,7 @@ proc appActivate(app: Application) = window.actionMap.addAction(action) action = newSimpleAction("help") - discard action.connect("activate", toggleHelp, helpText) + discard action.connect("activate", toggleHelp, helpBox) app.setAccelsForAction("win.help", "H") window.actionMap.addAction(action) @@ -252,7 +264,7 @@ proc appActivate(app: Application) = window.showAll # Help is only shown on demand - helpText.hide + helpBox.hide # Setting the inital image # Fix 1 second timeout to make sure all other initialization has finished diff --git a/src/resources/app.css b/src/resources/app.css index ddd5838..013c063 100644 --- a/src/resources/app.css +++ b/src/resources/app.css @@ -2,7 +2,7 @@ window { background: black; font-size: 30px; } -label { +box { background-color: rgba(255, 255, 255, .75); border: 2px solid gray; border-radius: 5px;