diff options
| -rw-r--r-- | TODO.norg | 1 | ||||
| -rw-r--r-- | bin/Main.hs | 2 | ||||
| -rw-r--r-- | specs/Specs/AppStateSpec.hs | 95 | ||||
| -rw-r--r-- | src/Chelleport.hs | 1 | ||||
| -rw-r--r-- | src/Chelleport/AppShell.hs | 22 | ||||
| -rw-r--r-- | src/Chelleport/AppState.hs | 56 | ||||
| -rw-r--r-- | src/Chelleport/Types.hs | 3 | ||||
| -rw-r--r-- | src/Chelleport/View.hs | 5 |
8 files changed, 105 insertions, 80 deletions
@@ -2,6 +2,7 @@ - ( ) Sort ocr match result by position on screen (top to bottom, left to right) - ( ) TextStyle for drawText - ( ) Middle click + - ( ) Separate state for hint modes into ModeHint constructor - (-) Optimize speed of ocr * Later diff --git a/bin/Main.hs b/bin/Main.hs index 007fb5e..03c0904 100644 --- a/bin/Main.hs +++ b/bin/Main.hs @@ -1,8 +1,8 @@ module Main where import qualified Chelleport -import Chelleport.Args (Configuration (configShowHelp)) import qualified Chelleport.Args as Args +import Chelleport.Types import qualified System.Environment import System.Exit (exitFailure) diff --git a/specs/Specs/AppStateSpec.hs b/specs/Specs/AppStateSpec.hs index 9864a0e..44da414 100644 --- a/specs/Specs/AppStateSpec.hs +++ b/specs/Specs/AppStateSpec.hs @@ -1,7 +1,6 @@ module Specs.AppStateSpec where import Chelleport.AppState (initialState, update) -import Chelleport.Args (Configuration (configMode)) import Chelleport.Types import Chelleport.Utils (uniq) import Control.Monad (join) @@ -12,6 +11,7 @@ import TestUtils test :: SpecWith () test = do + let flush = pure () describe "#initialState" $ do let config = def @@ -46,11 +46,11 @@ test = do let currentState = defaultState {stateRepetition = 1} it "hides window, triggers mouse click and shows the window again" $ do - (_, mock) <- runWithMocks $ update currentState $ ChainMouseClick LeftClick + (_, mock) <- runWithMocks $ update flush currentState $ ChainMouseClick LeftClick mock `shouldContainCalls` [Mock_hideWindow, Mock_clickMouseButton LeftClick, Mock_showWindow] it "continues with action ResetKeys without updating state" $ do - ((nextState, action), _) <- runWithMocks $ update currentState $ ChainMouseClick LeftClick + ((nextState, action), _) <- runWithMocks $ update flush currentState $ ChainMouseClick LeftClick action `shouldBe` Just ResetKeys nextState `shouldBe` currentState @@ -58,11 +58,11 @@ test = do let currentState = defaultState {stateRepetition = 3} it "resets repetition back to 1" $ do - ((nextState, _), _) <- runWithMocks $ update currentState $ ChainMouseClick LeftClick + ((nextState, _), _) <- runWithMocks $ update flush currentState $ ChainMouseClick LeftClick nextState `shouldBe` currentState {stateRepetition = 1} it "clicks multiple times" $ do - (_, mock) <- runWithMocks $ update currentState $ ChainMouseClick LeftClick + (_, mock) <- runWithMocks $ update flush currentState $ ChainMouseClick LeftClick mock `shouldContainCalls` [ Mock_hideWindow, Mock_clickMouseButton LeftClick, @@ -84,11 +84,11 @@ test = do it "continues with MoveMousePosition" $ do ((_, action), _) <- runWithMocks $ do Mock_getMousePointerPosition `mockReturns` (42, 42) - update currentState $ IncrementMouseCursor (10, -5) + update flush currentState $ IncrementMouseCursor (10, -5) action `shouldBe` Just (MoveMousePosition (52, 37)) it "does update state" $ do - ((state, _), _) <- runWithMocks $ update currentState $ IncrementMouseCursor (10, -5) + ((state, _), _) <- runWithMocks $ update flush currentState $ IncrementMouseCursor (10, -5) state `shouldBe` currentState context "when repetition is more than 1" $ do @@ -97,29 +97,29 @@ test = do it "multiplies increment" $ do ((_, action), _) <- runWithMocks $ do Mock_getMousePointerPosition `mockReturns` (42, 42) - update currentState $ IncrementMouseCursor (10, -5) + update flush currentState $ IncrementMouseCursor (10, -5) action `shouldBe` Just (MoveMousePosition (92, 17)) context "with action MouseDragEnd" $ do let currentState = defaultState it "hides window, stops dragging and shows the window again" $ do - (_, mock) <- runWithMocks $ update currentState MouseDragEnd + (_, mock) <- runWithMocks $ update flush currentState MouseDragEnd mock `shouldContainCalls` [Mock_hideWindow, Mock_releaseMouseButton, Mock_showWindow] it "does not continue or update state" $ do - (result, _) <- runWithMocks $ update currentState MouseDragStart + (result, _) <- runWithMocks $ update flush currentState MouseDragStart result `shouldBe` (currentState, Nothing) context "with action MouseDragStart" $ do let currentState = defaultState it "hides window, starts dragging and shows the window again" $ do - (_, mock) <- runWithMocks $ update currentState MouseDragStart + (_, mock) <- runWithMocks $ update flush currentState MouseDragStart mock `shouldContainCalls` [Mock_hideWindow, Mock_pressMouseButton, Mock_showWindow] it "does not continue or update state" $ do - (result, _) <- runWithMocks $ update currentState MouseDragStart + (result, _) <- runWithMocks $ update flush currentState MouseDragStart result `shouldBe` (currentState, Nothing) context "with action MouseDragToggle" $ do @@ -127,22 +127,22 @@ test = do let currentState = defaultState {stateIsDragging = True} it "toggles dragging state" $ do - ((state, _), _) <- runWithMocks $ update currentState MouseDragToggle + ((state, _), _) <- runWithMocks $ update flush currentState MouseDragToggle state `shouldBe` state {stateIsDragging = False} it "continues with action MouseDragEnd" $ do - ((_, action), _) <- runWithMocks $ update currentState MouseDragToggle + ((_, action), _) <- runWithMocks $ update flush currentState MouseDragToggle action `shouldBe` Just MouseDragEnd context "when is dragging is false" $ do let currentState = defaultState {stateIsDragging = False} it "toggles dragging state" $ do - ((state, _), _) <- runWithMocks $ update currentState MouseDragToggle + ((state, _), _) <- runWithMocks $ update flush currentState MouseDragToggle state `shouldBe` state {stateIsDragging = True} it "continues with action MouseDragStart" $ do - ((_, action), _) <- runWithMocks $ update currentState MouseDragToggle + ((_, action), _) <- runWithMocks $ update flush currentState MouseDragToggle action `shouldBe` Just MouseDragStart context "with action HandleKeyInput" $ do @@ -156,13 +156,13 @@ test = do context "when input key sequence has matching values in grid" $ do it "does not update" $ do - ((nextState, action), _) <- runWithMocks $ update currentState $ HandleKeyInput SDL.KeycodeZ + ((nextState, action), _) <- runWithMocks $ update flush currentState $ HandleKeyInput SDL.KeycodeZ action `shouldBe` Nothing nextState `shouldBe` currentState context "when input key sequence does not have matching values in grid" $ do it "adds key to key sequence" $ do - ((nextState, action), _) <- runWithMocks $ update currentState $ HandleKeyInput SDL.KeycodeE + ((nextState, action), _) <- runWithMocks $ update flush currentState $ HandleKeyInput SDL.KeycodeE action `shouldBe` Nothing nextState `shouldBe` currentState {stateKeySequence = "DE"} @@ -171,14 +171,14 @@ test = do context "when input key sequence does not have matching values in grid" $ do it "adds key to key sequence and enables isMatched" $ do - ((nextState, _), _) <- runWithMocks $ update currentState $ HandleKeyInput SDL.KeycodeF + ((nextState, _), _) <- runWithMocks $ update flush currentState $ HandleKeyInput SDL.KeycodeF nextState `shouldBe` currentState {stateKeySequence = "DEF", stateIsMatched = True} it "continues with MoveMousePosition action at center of matched cell" $ do ((_, action), _) <- runWithMocks $ do Mock_windowSize `mockReturns` mockWindowSize Mock_windowPosition `mockReturns` mockWindowPosition - update currentState $ HandleKeyInput SDL.KeycodeF + update flush currentState $ HandleKeyInput SDL.KeycodeF action `shouldBe` Just (MoveMousePosition (1640, 370)) context "with action MoveMouseInDirection" $ do @@ -188,64 +188,74 @@ test = do it "continues to increment movement" $ do ((_, action), _) <- runWithMocks $ do Mock_windowSize `mockReturns` mockWindowSize - update currentState $ MoveMouseInDirection DirUp + update flush currentState $ MoveMouseInDirection DirUp action `shouldBe` Just (IncrementMouseCursor (0, -33)) context "when direction is down" $ do it "continues to increment movement" $ do ((_, action), _) <- runWithMocks $ do Mock_windowSize `mockReturns` mockWindowSize - update currentState $ MoveMouseInDirection DirDown + update flush currentState $ MoveMouseInDirection DirDown action `shouldBe` Just (IncrementMouseCursor (0, 33)) context "when direction is left" $ do it "continues to increment movement" $ do ((_, action), _) <- runWithMocks $ do Mock_windowSize `mockReturns` mockWindowSize - update currentState $ MoveMouseInDirection DirLeft + update flush currentState $ MoveMouseInDirection DirLeft action `shouldBe` Just (IncrementMouseCursor (-60, 0)) context "when direction is right" $ do it "continues to increment movement" $ do ((_, action), _) <- runWithMocks $ do Mock_windowSize `mockReturns` mockWindowSize - update currentState $ MoveMouseInDirection DirRight + update flush currentState $ MoveMouseInDirection DirRight action `shouldBe` Just (IncrementMouseCursor (60, 0)) context "with action MoveMousePosition" $ do let currentState = defaultState it "moves mouse pointer to the given coordinates" $ do - (_, mock) <- runWithMocks $ update currentState $ MoveMousePosition (23, 320) + (_, mock) <- runWithMocks $ update flush currentState $ MoveMousePosition (23, 320) mock `shouldHaveCalled` Mock_moveMousePointer 23 320 it "does not continue or update state" $ do - (result, _) <- runWithMocks $ update currentState $ MoveMousePosition (0, 0) + (result, _) <- runWithMocks $ update flush currentState $ MoveMousePosition (0, 0) result `shouldBe` (currentState, Nothing) context "with action ResetKeys" $ do let currentState = defaultState {stateRepetition = 5} it "resets state without any action" $ do - ((nextState, action), _) <- runWithMocks $ update currentState ResetKeys + ((nextState, action), _) <- runWithMocks $ update flush currentState ResetKeys action `shouldBe` Nothing nextState `shouldBe` currentState {stateKeySequence = [], stateIsMatched = False, stateRepetition = 1} context "with action SetMode" $ do let currentState = defaultState + it "updates mode in state and continues to initialize mode" $ do + ((nextState, action), _) <- runWithMocks $ update flush currentState $ SetMode defaultHintsMode + nextState `shouldBe` currentState {stateMode = defaultHintsMode, stateIsModeInitialized = False} + action `shouldBe` Just InitializeMode + + context "with action InitializeMode" $ do context "when mode is ModeHints" $ do - it "updates mode in state" $ do - ((nextState, action), _) <- runWithMocks $ update currentState $ SetMode defaultHintsMode - nextState `shouldBe` currentState {stateMode = defaultHintsMode} + let currentState = defaultState {stateMode = defaultHintsMode, stateIsModeInitialized = False} + + it "updates initialization state to true" $ do + ((nextState, action), _) <- runWithMocks $ update flush currentState InitializeMode + nextState `shouldBe` currentState {stateIsModeInitialized = True} action `shouldBe` Nothing context "when mode is ModeSearch" $ do + let currentState = defaultState {stateMode = defaultSearchMode, stateIsModeInitialized = False} + it "captures screenshot for word search" $ do ((_, _), mock) <- runWithMocks $ do Mock_windowSize `mockReturns` mockWindowSize Mock_windowPosition `mockReturns` mockWindowPosition - update currentState $ SetMode defaultSearchMode + update flush currentState InitializeMode mock `shouldHaveCalled` Mock_captureScreenshot (mockWindowOffsetX, mockWindowOffsetY) (mockWindowWidth, mockWindowHeight) it "updates mode in state with ocr words" $ do @@ -255,10 +265,11 @@ test = do Mock_windowPosition `mockReturns` mockWindowPosition Mock_captureScreenshot mockWindowPosition mockWindowSize `mockReturns` "mock-filename" Mock_getWordsInImage "mock-filename" `mockReturns` [matchWord] - update currentState $ SetMode defaultSearchMode + update flush currentState InitializeMode nextState `shouldBe` currentState - { stateMode = + { stateIsModeInitialized = True, + stateMode = defaultSearchMode { searchWords = [matchWord], searchFilteredWords = [matchWord] @@ -269,11 +280,11 @@ test = do let currentState = defaultState it "shuts down app" $ do - (_, mock) <- runWithMocks $ update currentState ShutdownApp + (_, mock) <- runWithMocks $ update flush currentState ShutdownApp mock `shouldHaveCalled` Mock_shutdownApp it "does not continue or update state" $ do - (result, _) <- runWithMocks $ update currentState ShutdownApp + (result, _) <- runWithMocks $ update flush currentState ShutdownApp result `shouldBe` (currentState, Nothing) context "with action TriggerMouseClick" $ do @@ -281,11 +292,11 @@ test = do let currentState = defaultState {stateRepetition = 1} it "hides window and triggers mouse click" $ do - (_, mock) <- runWithMocks $ update currentState $ TriggerMouseClick LeftClick + (_, mock) <- runWithMocks $ update flush currentState $ TriggerMouseClick LeftClick mock `shouldContainCalls` [Mock_hideWindow, Mock_clickMouseButton LeftClick] it "continues with action ShutdownApp without updating state" $ do - ((nextState, action), _) <- runWithMocks $ update currentState $ TriggerMouseClick LeftClick + ((nextState, action), _) <- runWithMocks $ update flush currentState $ TriggerMouseClick LeftClick action `shouldBe` Just ShutdownApp nextState `shouldBe` currentState @@ -293,11 +304,11 @@ test = do let currentState = defaultState {stateRepetition = 3} it "resets repetition back to 1" $ do - ((nextState, _), _) <- runWithMocks $ update currentState $ TriggerMouseClick LeftClick + ((nextState, _), _) <- runWithMocks $ update flush currentState $ TriggerMouseClick LeftClick nextState `shouldBe` currentState {stateRepetition = 1} it "clicks multiple times" $ do - (_, mock) <- runWithMocks $ update currentState $ TriggerMouseClick LeftClick + (_, mock) <- runWithMocks $ update flush currentState $ TriggerMouseClick LeftClick mock `shouldContainCalls` [ Mock_hideWindow, Mock_clickMouseButton LeftClick, @@ -309,13 +320,13 @@ test = do let currentState = defaultState it "updates repetition without any action" $ do - ((nextState, action), _) <- runWithMocks $ update currentState $ UpdateRepetition 7 + ((nextState, action), _) <- runWithMocks $ update flush currentState $ UpdateRepetition 7 action `shouldBe` Nothing nextState `shouldBe` currentState {stateRepetition = 7} context "when count is 0" $ do it "updates repetition to 1" $ do - ((nextState, action), _) <- runWithMocks $ update currentState $ UpdateRepetition 0 + ((nextState, action), _) <- runWithMocks $ update flush currentState $ UpdateRepetition 0 action `shouldBe` Nothing nextState `shouldBe` currentState {stateRepetition = 1} @@ -323,6 +334,6 @@ test = do let currentState = defaultState it "updates shift state without any action" $ do - ((nextState, action), _) <- runWithMocks $ update currentState $ UpdateShiftState True + ((nextState, action), _) <- runWithMocks $ update flush currentState $ UpdateShiftState True action `shouldBe` Nothing nextState `shouldBe` currentState {stateIsShiftPressed = True} diff --git a/src/Chelleport.hs b/src/Chelleport.hs index 02977c9..029821e 100644 --- a/src/Chelleport.hs +++ b/src/Chelleport.hs @@ -2,7 +2,6 @@ module Chelleport where import Chelleport.AppShell (setupAppShell) import qualified Chelleport.AppState as AppState -import Chelleport.Args (Configuration) import Chelleport.Context (initializeContext) import Chelleport.Control (anyAlphabetic, anyDigit, checkKey, ctrl, eventToKeycode, hjkl, hjklDirection, key, pressed, released, shift) import Chelleport.KeySequence (keycodeToInt, toKeyChar) diff --git a/src/Chelleport/AppShell.hs b/src/Chelleport/AppShell.hs index d48e06b..06ffa1a 100644 --- a/src/Chelleport/AppShell.hs +++ b/src/Chelleport/AppShell.hs @@ -1,9 +1,8 @@ -module Chelleport.AppShell (setupAppShell, MonadAppShell (..)) where +module Chelleport.AppShell where import Chelleport.Config import Chelleport.Control (MonadControl (releaseMouseButton)) import Chelleport.Types -import Control.Monad (foldM) import Control.Monad.IO.Class (MonadIO (liftIO)) import Control.Monad.RWS (MonadReader (ask), asks) import qualified Graphics.X11 as X11 @@ -29,7 +28,9 @@ instance (MonadIO m) => MonadAppShell (AppM m) where X11.closeDisplay $ ctxX11Display ctx exitSuccess -type Update m state appAction = state -> appAction -> m (state, Maybe appAction) +type Flush m = m () + +type Update m state appAction = Flush m -> state -> appAction -> m (state, Maybe appAction) type EventHandler state appAction = state -> SDL.Event -> Maybe appAction @@ -38,7 +39,7 @@ type View m state = state -> m () type Initializer m state appAction = m (state, Maybe appAction) setupAppShell :: - (MonadIO m) => + (MonadIO m, Show state) => DrawContext -> Initializer m state appAction -> Update m state appAction -> @@ -50,20 +51,21 @@ setupAppShell (DrawContext {ctxRenderer = renderer}) getInitState update eventHa appLoop state where appLoop currentState = do + renderScreen currentState + newState <- SDL.waitEvent >>= evaluateEvent currentState + appLoop newState + + renderScreen state = do SDL.rendererDrawColor renderer $= colorBackground SDL.clear renderer - draw currentState + draw state SDL.present renderer - newState <- SDL.pollEvents >>= foldM evaluateEvent currentState - - appLoop newState - evaluateEvent state event = maybe (pure state) (updateState state) (eventHandler state event) updateState state action = - update state action >>= evalUpdateResult + update (renderScreen state) state action >>= evalUpdateResult evalUpdateResult (state, Nothing) = pure state evalUpdateResult (state, Just action) = updateState state action diff --git a/src/Chelleport/AppState.hs b/src/Chelleport/AppState.hs index 168cacf..6c2de9c 100644 --- a/src/Chelleport/AppState.hs +++ b/src/Chelleport/AppState.hs @@ -1,7 +1,6 @@ module Chelleport.AppState (initialState, update) where -import Chelleport.AppShell (MonadAppShell (hideWindow, showWindow, shutdownApp)) -import Chelleport.Args (Configuration (configMode)) +import Chelleport.AppShell (MonadAppShell (hideWindow, showWindow, shutdownApp), Update) import Chelleport.Control (MonadControl (..), directionalIncrement, hjklDirection) import Chelleport.Draw (MonadDraw (windowPosition, windowSize), pointerPositionIncrement, screenPositionFromCellPosition, wordPosition) import Chelleport.KeySequence (findMatchPosition, generateGrid, nextChars, toKeyChar) @@ -23,16 +22,16 @@ initialState config = do columns = 16 hintKeys = ['A' .. 'Z'] -update :: (MonadAppShell m, MonadDraw m, MonadControl m, MonadOCR m) => State -> AppAction -> m (State, Maybe AppAction) +update :: (MonadAppShell m, MonadDraw m, MonadControl m, MonadOCR m) => Update m State AppAction -- Chain clicks -update state (ChainMouseClick btn) = do +update _ state (ChainMouseClick btn) = do hideWindow replicateM_ (stateRepetition state) $ clickMouseButton btn showWindow pure (state {stateRepetition = 1}, Just ResetKeys) -- HINTS MODE: Act on key inputs -update state@(State {stateMode = ModeHints}) (HandleKeyInput keycode) = do +update _ state@(State {stateMode = ModeHints}) (HandleKeyInput keycode) = do case (toKeyChar keycode, validNextKeys) of (Just keyChar, Just validChars') | stateIsMatched state && keyChar `elem` ("HJKL" :: String) -> do @@ -48,7 +47,7 @@ update state@(State {stateMode = ModeHints}) (HandleKeyInput keycode) = do validNextKeys = nextChars (stateKeySequence state) (stateGrid state) -- SEARCH MODE: Act on key inputs -update state@(State {stateMode = ModeSearch {searchWords, searchInputText}}) (HandleKeyInput keycode) = do +update _ state@(State {stateMode = ModeSearch {searchWords, searchInputText}}) (HandleKeyInput keycode) = do case toKeyChar keycode of Just keyChar -> do let searchText = searchInputText ++ [toLower keyChar] @@ -72,7 +71,7 @@ update state@(State {stateMode = ModeSearch {searchWords, searchInputText}}) (Ha | otherwise = Fuzzy.original <$> Fuzzy.filter text searchWords "" "" matchText False -- Increment highlighted index for search mode -update state (IncrementHighlightIndex n) = do +update _ state (IncrementHighlightIndex n) = do case stateMode state of ModeSearch {} -> do action <- traverse (fmap MoveMousePosition . wordPosition) highlightedWord @@ -88,43 +87,43 @@ update state (IncrementHighlightIndex n) = do _ -> pure (state, Nothing) -- Move mouse incrementally -update state (IncrementMouseCursor (incX, incY)) = do +update _ state (IncrementMouseCursor (incX, incY)) = do (curX, curY) <- getMousePointerPosition let count = stateRepetition state let pos = (cIntToInt curX + count * incX, cIntToInt curY + count * incY) pure (state {stateRepetition = 1}, Just $ MoveMousePosition pos) -- Mouse button release -update state MouseDragEnd = do +update _ state MouseDragEnd = do hideWindow releaseMouseButton showWindow pure (state {stateRepetition = 1}, Nothing) -- Mouse button press -update state MouseDragStart = do +update _ state MouseDragStart = do hideWindow pressMouseButton showWindow pure (state {stateRepetition = 1}, Nothing) -- Mouse dragging -update state MouseDragToggle +update _ state MouseDragToggle | stateIsDragging state = pure (state {stateIsDragging = False}, Just MouseDragEnd) | otherwise = do pure (state {stateIsDragging = True}, Just MouseDragStart) -- Apply movement in given direction -update state (MoveMouseInDirection direction) = do +update _ state (MoveMouseInDirection direction) = do incr <- pointerPositionIncrement state pure (state, Just $ IncrementMouseCursor $ directionalIncrement incr direction) -- Move mouse to given position -update state (MoveMousePosition (x, y)) = do +update _ state (MoveMousePosition (x, y)) = do moveMousePointer (intToCInt x) (intToCInt y) pure (state, Nothing) -- Reset entered key sequence and state -update state ResetKeys = do +update _ state ResetKeys = do pure ( state { stateKeySequence = [], @@ -139,33 +138,40 @@ update state ResetKeys = do resetMode (ModeSearch {searchWords}) = defaultSearchMode {searchWords = searchWords, searchFilteredWords = searchWords} --- Set mode -update state (SetMode mode) = do - case mode of - ModeHints -> pure (state {stateMode = mode}, Nothing) +-- Initialize current mode +update flush state InitializeMode = + case stateMode state of + ModeHints -> pure (state {stateIsModeInitialized = True}, Nothing) ModeSearch {} -> do position <- windowPosition size <- windowSize - screenshot <- hideWindow >> captureScreenshot position size <* showWindow + hideWindow + screenshot <- captureScreenshot position size + showWindow + flush matches <- getWordsInImage screenshot - let updatedMode = mode {searchWords = matches, searchFilteredWords = matches} - pure (state {stateMode = updatedMode}, Nothing) + let updatedMode = (stateMode state) {searchWords = matches, searchFilteredWords = matches} + pure (state {stateMode = updatedMode, stateIsModeInitialized = True}, Nothing) + +-- Set mode +update _ state (SetMode mode) = do + pure (state {stateMode = mode, stateIsModeInitialized = False}, Just InitializeMode) -- Cleanup everything and exit -update state ShutdownApp = do +update _ state ShutdownApp = do shutdownApp pure (state, Nothing) -- Trigger click -update state (TriggerMouseClick btn) = do +update _ state (TriggerMouseClick btn) = do hideWindow replicateM_ (stateRepetition state) $ clickMouseButton btn pure (state {stateRepetition = 1}, Just ShutdownApp) -- Set repetition count -update state (UpdateRepetition count) = do +update _ state (UpdateRepetition count) = do pure (state {stateRepetition = max 1 count}, Nothing) -- Set/unset whether shift is pressed -update state (UpdateShiftState shiftPressed) = +update _ state (UpdateShiftState shiftPressed) = pure (state {stateIsShiftPressed = shiftPressed}, Nothing) diff --git a/src/Chelleport/Types.hs b/src/Chelleport/Types.hs index ae05dad..cc1a4c3 100644 --- a/src/Chelleport/Types.hs +++ b/src/Chelleport/Types.hs @@ -47,6 +47,7 @@ data State = State stateIsShiftPressed :: Bool, stateIsDragging :: Bool, stateRepetition :: Int, + stateIsModeInitialized :: Bool, stateMode :: Mode } deriving (Show, Eq) @@ -60,6 +61,7 @@ defaultAppState = stateIsShiftPressed = False, stateIsDragging = False, stateRepetition = 1, + stateIsModeInitialized = False, stateMode = ModeHints } @@ -71,6 +73,7 @@ data AppAction | HandleKeyInput SDL.Keycode | IncrementHighlightIndex Int | IncrementMouseCursor (Int, Int) + | InitializeMode | MouseDragEnd | MouseDragStart | MouseDragToggle diff --git a/src/Chelleport/View.hs b/src/Chelleport/View.hs index 202c636..790b3f7 100644 --- a/src/Chelleport/View.hs +++ b/src/Chelleport/View.hs @@ -19,8 +19,11 @@ getSearchText :: State -> String getSearchText state = case stateMode state of ModeHints -> "" ModeSearch {searchInputText, searchFilteredWords, searchHighlightedIndex} -> - "Searching (" ++ matchCount ++ "): " ++ searchInputText + searchText where + searchText + | stateIsModeInitialized state = "Searching (" ++ matchCount ++ "): " ++ searchInputText + | otherwise = "Loading..." matchCount | isEmpty searchFilteredWords = "0/0" | otherwise = show (searchHighlightedIndex + 1) ++ "/" ++ show (length searchFilteredWords) |
