Refactor code to separate View/Logic; Add clue widget - crossword.koplugin - Unnamed repository; edit this file 'description' to name the repository. (DIR) Log (DIR) Files (DIR) Refs (DIR) Submodules (DIR) README (DIR) LICENSE --- (DIR) commit 2634a8e4f825bef8761e798e488e121003bffdbe (DIR) parent 1dc559aef64abdc2dd6effc6e857586f839c9e20 (HTM) Author: Scarlett <social@scarlettmcallister.com> Date: Sat, 11 Dec 2021 16:54:23 -0400 Refactor code to separate View/Logic; Add clue widget Diffstat: A gridclue.lua | 50 +++++++++++++++++++++++++++++++ A gridrow.lua | 36 +++++++++++++++++++++++++++++++ A gridsquare.lua | 78 +++++++++++++++++++++++++++++++ A gridview.lua | 132 +++++++++++++++++++++++++++++++ M main.lua | 40 ++++++++++++++----------------- A puzzle.lua | 56 +++++++++++++++++++++++++++++++ D puzzlerow.lua | 37 ------------------------------- D puzzlesquare.lua | 92 ------------------------------- D puzzleview.lua | 120 ------------------------------- 9 files changed, 370 insertions(+), 271 deletions(-) --- (DIR) diff --git a/gridclue.lua b/gridclue.lua @@ -0,0 +1,50 @@ +local Blitbuffer = require("ffi/blitbuffer") +local CenterContainer = require("ui/widget/container/centercontainer") +local InputContainer = require("ui/widget/container/inputcontainer") +local Font = require("ui/font") +local Geom = require("ui/geometry") +local FrameContainer = require("ui/widget/container/framecontainer") +local TextWidget = require("ui/widget/textwidget") +local TextBoxWidget = require("ui/widget/textboxwidget") + +local logger = require("logger") + +local GridClue = InputContainer:new{ + height = nil, + width = nil, + clue_font_face = "infofont", + clue_font_size = nil, + clue_value = nil, +} + +function GridClue:init() + self.clue_font_size = TextBoxWidget:getFontSizeToFitHeight(self.height, 1, 0.3) + + self.clue_widget = TextWidget:new{ + text = self.clue_value, + face = Font:getFace(self.clue_font_face, self.clue_font_size), + fgcolor = Blitbuffer.COLOR_WHITE, + padding = 0, + bold = true, + } + + self[1] = FrameContainer:new{ + width = self.width, + height = self.height, + padding = 0, + margin = self.margin or 0, + bordersize = 0, + -- Keep the letter centered + CenterContainer:new{ + dimen = Geom:new{ + w = self.width, + h = self.height, + }, + padding = 0, + -- Add the letter + self.clue_widget, + }, + } +end + +return GridClue (DIR) diff --git a/gridrow.lua b/gridrow.lua @@ -0,0 +1,36 @@ +local InputContainer = require("ui/widget/container/inputcontainer") +local HorizontalGroup = require("ui/widget/horizontalgroup") +local FrameContainer = require("ui/widget/container/framecontainer") + +local GridRow = InputContainer:new{ + width = nil, + height = nil, + padding = nil, +} + +function GridRow:init() + self.squares = {} +end + +function GridRow:addSquare(square) + table.insert(self.squares, square) +end + +function GridRow:update() + local hori = HorizontalGroup:new{} + + for num, square in ipairs(self.squares) do + table.insert(hori, square) + end + + self[1] = FrameContainer:new{ + width = self.width, + height = self.height, + bordersize = 0, + padding = 0, + margin = 0, + hori + } +end + +return GridRow (DIR) diff --git a/gridsquare.lua b/gridsquare.lua @@ -0,0 +1,78 @@ +local Blitbuffer = require("ffi/blitbuffer") +local CenterContainer = require("ui/widget/container/centercontainer") +local InputContainer = require("ui/widget/container/inputcontainer") +local Font = require("ui/font") +local Geom = require("ui/geometry") +local FrameContainer = require("ui/widget/container/framecontainer") +local OverlapGroup = require("ui/widget/overlapgroup") +local TextWidget = require("ui/widget/textwidget") +local TextBoxWidget = require("ui/widget/textboxwidget") + +local logger = require("logger") + +local GridSquare = InputContainer:new{ + height = nil, + width = nil, + letter_font_face = "infofont", + letter_font_size = nil, + number_font_face = "infont", + number_font_size = nil, + margin = nil, + letter_value = nil, + number_value = nil, +} + +function GridSquare:init() + -- Set up the right bg color, letter, etc. + local bg_color = self.letter_value ~= "." and + Blitbuffer.COLOR_WHITE or + Blitbuffer.COLOR_BLACK + + self.letter_font_size = TextBoxWidget:getFontSizeToFitHeight(self.height, 1, 0.3) + self.number_font_size = self.letter_font_size / 2 + + -- Maybe a letter input by the player. + self.letter_widget = TextWidget:new{ + text = self.letter_value, + face = Font:getFace(self.letter_font_face, self.letter_font_size), + fgcolor = Blitbuffer.COLOR_BLACK, + padding = 0, + bold = true, + } + -- Maybe a number that corresponds to a question. + self.number_widget = TextWidget:new{ + text = self.number_value, + face = Font:getFace(self.number_font_face, self.number_font_size), + fgcolor = Blitbuffer.COLOR_BLACK, + padding = 0, + bold = true, + } + -- This is the container for the letter and number. + self[1] = FrameContainer:new{ + width = self.width, + height = self.height, + color = Blitbuffer.COLOR_WHITE, + background = bg_color, + padding = 0, + margin = self.margin or 0, + bordersize = 0, + OverlapGroup:new{ + dimen = { w = self.width }, + padding = 0, + -- Keep the letter centered + CenterContainer:new{ + dimen = Geom:new{ + w = self.width, + h = self.height, + }, + padding = 0, + -- Add the letter + self.letter_widget, + }, + -- Add the number + self.number_widget, + }, + } +end + +return GridSquare (DIR) diff --git a/gridview.lua b/gridview.lua @@ -0,0 +1,132 @@ +local Blitbuffer = require("ffi/blitbuffer") +local Device = require("device") +local Screen = Device.screen +local Size = require("ui/size") +local Geom = require("ui/geometry") +local GestureRange = require("ui/gesturerange") +local FrameContainer = require("ui/widget/container/framecontainer") +local InputContainer = require("ui/widget/container/inputcontainer") +local VerticalGroup = require("ui/widget/verticalgroup") +local logger = require("logger") + +local GridRow = require("gridrow") +local GridSquare = require("gridsquare") +local GridClue = require("gridclue") + +local GridView = InputContainer:new{ + width = nil, + height = nil, + size = { + cols = nil, + rows = nil, + }, + on_tap_callback = nil +} + +function GridView:init() + self.dimen = Geom:new{ + w = self.width or Screen:getWidth(), + h = self.height or Screen:getHeight(), + } + self.outer_padding = Size.padding.large + self.inner_padding = Size.padding.small + self.inner_dimen = Geom:new{ + w = self.dimen.w - 2 * self.outer_padding, + h = self.dimen.h - self.outer_padding, -- no bottom padding + } + self.content_width = self.inner_dimen.w + -- The pixel dimensions of the squares. Calculate the initial width based on the size + -- of the device and the number of columns. Then make a minor adjustment to account for + -- the margins. To do this, divide margin in 4 and multiply by the number of columns. + self.square_margin = Size.border.window + self.square_width = math.floor( + (self.dimen.w - (2 * self.outer_padding) - (2 * self.inner_padding)) + / self.size.cols) - ((self.square_margin / 4) * (6)) -- 6 works here for some reason, although in my head + -- (cont) it should be self.size.cols because that's what we're adjusting for. + self.square_height = self.square_width + -- Register the event listener + self.ges_events.Tap = { + GestureRange:new{ + ges = "tap", + range = function() + return self.dimen + end, + }, + } +end + +function GridView:render() + -- Build the row and add the squares. + self.rows_view = VerticalGroup:new { border = 0 } + for i, l in ipairs(self.grid) do + local row = self:buildRow(l) + table.insert(self.rows_view, row) + end + -- Build the clue. + self.grid_clue = GridClue:new{ + width = self.inner_dimen.w, + height = self.square_height, + clue_value = self.active_clue + } + -- Build the container. + self[1] = FrameContainer:new{ + width = self.dimen.w, + height = self.dimen.h, + padding = self.outer_padding, + padding_bottom = 0, + margin = 0, + bordersize = 0, + background = Blitbuffer.COLOR_BLACK, + VerticalGroup:new{ + align = "center", + background = Blitbuffer.COLOR_GRAY, + -- Add the rows vertical group. + self.rows_view, + self.grid_clue, + } + } +end + +function GridView:onTap(_, ges) + -- Temp for debuggery + -- Find the square that's been tapped + -- so we want to find the square + -- and we can expedite that by getting the correct row, first, + -- which is given by the square_height stuff... we will have to account for margins, too. + -- self.square_margin + -- self.square_height + local y = ges.pos.y + local x = ges.pos.x + -- so, get the row number + local row_num = math.ceil(x / (self.square_height)) + local col_num = math.ceil(y / self.square_width) + -- If a callback's been set, we need to send back the + -- coordinates so some genius can do something else. + if self.on_tap_callback then + self.on_tap_callback(row_num, col_num) + end +end + +-- Given a table containing letters, build a row containing +-- squares with said letters. +function GridView:buildRow(squares, row_num) + local row = GridRow:new{ + width = self.inner_dimen.w, + height = self.square_height, + } + for col_num, square in ipairs(squares) do + row:addSquare(GridSquare:new{ + width = self.square_width, + height = self.square_height, + pos_x = col_num, + pos_y = row_num, + margin = self.square_margin, + letter_value = square.letter, + number_value = square.number, + }) + end + row:update() + return row +end + +return GridView (DIR) diff --git a/main.lua b/main.lua @@ -84,7 +84,7 @@ function Crossword:setPuzzlesDirectory() self:lazyInitialization() end -function Crossword:gameView() +function Crossword:loadPuzzle() local file_path = ("%s/%s"):format(self.puzzle_dir, "/1990/01/01.json") local file, err = io.open(file_path, "rb") @@ -95,33 +95,29 @@ function Crossword:gameView() local file_content = file:read("*all") file:close() - local puzzle = json.decode(file_content) - logger.dbg(puzzle) - -- Create the grid, which contains the letters for - -- each row. - local grid = {} - local row = {} - for i, letter in ipairs(puzzle.grid) do - table.insert(row, { - letter = letter, - number = puzzle.gridnums[i], - }) - if i % 15 == 0 then - table.insert(grid, row) - row = {} - end - end + local Puzzle = require("puzzle") + local puzzle = Puzzle:new{} + puzzle:init(json.decode(file_content)) + return puzzle +end - local PuzzleView = require("puzzleview") - PuzzleView = PuzzleView:new{ +function Crossword:gameView() + local puzzle = self:loadPuzzle() + + local GridView = require("gridview") + GridView = GridView:new{ size = { cols = puzzle.size.cols, rows = puzzle.size.rows }, - grid = grid + grid = puzzle.grid, + active_clue = "This is the hint", + on_tap_callback = function(row, col) + logger.dbg(puzzle:getSquareAtPos(row, col)) + end } - - UIManager:show(PuzzleView) + UIManager:show(GridView) + GridView:render() end return Crossword (DIR) diff --git a/puzzle.lua b/puzzle.lua @@ -0,0 +1,56 @@ +local logger = require("logger") + +local Puzzle = { + json_object = nil, + size = { + cols = nil, + rows = nil, + }, + grid = nil, +} + +function Puzzle:new(o) + o = o or {} -- create object if user does not provide one + setmetatable(o, self) + self.__index = self + return o +end + +function Puzzle:init(json_object) + -- Lazy error checking + if not json_object then + logger.dbg("Puzzle: json_object must be set for puzzle to be created.") + return false + end + -- Onto the initialization + self.size = json_object.size + self.grid = {} + local row = {} -- Start with an empty row to collect squares. + for i, letter in ipairs(json_object.grid) do + local grid_num = json_object.gridnums[i] + -- Add a square to the row + table.insert(row, { + letter = letter and + letter or + "", + number = grid_num ~= 0 and + tostring(grid_num) or + "", + }) + -- Check whether to insert the row and reset the count. + if i % self.size.cols == 0 then + table.insert(self.grid, row) + row = {} -- Empty the row table to collect the new set of squares. + end + end +end + +function Puzzle:getGrid() + return self.grid +end + +function Puzzle:getSquareAtPos(row, col) + return self.grid[row][col] +end + +return Puzzle (DIR) diff --git a/puzzlerow.lua b/puzzlerow.lua @@ -1,37 +0,0 @@ -local InputContainer = require("ui/widget/container/inputcontainer") -local HorizontalGroup = require("ui/widget/horizontalgroup") -local HorizontalSpan = require("ui/widget/horizontalspan") -local FrameContainer = require("ui/widget/container/framecontainer") - -local Row = InputContainer:new{ - width = nil, - height = nil, - padding = nil, -} - -function Row:init() - self.squares = {} -end - -function Row:addSquare(square) - table.insert(self.squares, square) -end - -function Row:update() - local hori = HorizontalGroup:new{} - - for num, square in ipairs(self.squares) do - table.insert(hori, square) - end - - self[1] = FrameContainer:new{ - width = self.width, - height = self.height, - bordersize = 0, - padding = 0, - margin = 0, - hori - } -end - -return Row (DIR) diff --git a/puzzlesquare.lua b/puzzlesquare.lua @@ -1,92 +0,0 @@ -local Blitbuffer = require("ffi/blitbuffer") -local CenterContainer = require("ui/widget/container/centercontainer") -local InputContainer = require("ui/widget/container/inputcontainer") -local Font = require("ui/font") -local Geom = require("ui/geometry") -local FrameContainer = require("ui/widget/container/framecontainer") -local OverlapGroup = require("ui/widget/overlapgroup") -local TextWidget = require("ui/widget/textwidget") -local TextBoxWidget = require("ui/widget/textboxwidget") - -local logger = require("logger") - -local PuzzleSquare = InputContainer:new{ - letter_font_face = "infofont", - letter_font_size = nil, - number_font_face = "infont", - number_font_size = nil, - margin = nil, - solve = nil, -} - -function PuzzleSquare:init() - -- Lazy check to see if solve is set. - if not self.solve then - logger.dbg("PuzzleSquare: solve not set for square") - return - end - - -- Set up the right bg color, letter, etc. - local bg_color = self.solve.letter ~= "." and - Blitbuffer.COLOR_WHITE or - Blitbuffer.COLOR_BLACK - local letter = self.solve.letter and - self.solve.letter or - "" - local number = self.solve.number ~= 0 and - tostring(self.solve.number) or - "" - - self.letter_font_size = TextBoxWidget:getFontSizeToFitHeight(self.height, 1, 0.3) - self.number_font_size = self.letter_font_size / 2 - - -- This is the letter input by the player. - self.letter = TextWidget:new{ - text = letter, - face = Font:getFace(self.letter_font_face, self.letter_font_size), - fgcolor = Blitbuffer.COLOR_BLACK, - padding = 0, - bold = true, - } - -- This is the number that corresponds to the question. - -- Note that the number is not always set! - self.number = TextWidget:new{ - text = number, - face = Font:getFace(self.number_font_face, self.number_font_size), - fgcolor = Blitbuffer.COLOR_BLACK, - padding = 0, - bold = true, - } - -- This is the container for the letter and number. - self[1] = FrameContainer:new{ - width = self.width, - height = self.height, - color = Blitbuffer.COLOR_WHITE, - background = bg_color, - padding = 0, - margin = self.margin or 0, - bordersize = 0, - OverlapGroup:new{ - dimen = { w = self.width }, - padding = 0, - -- Keep the letter centered - CenterContainer:new{ - dimen = Geom:new{ - w = self.width, - h = self.height, - }, - padding = 0, - -- Add the letter - self.letter, - }, - -- Add the number - self.number, - }, - } -end - -function PuzzleSquare:onTap() - logger.dbg("TA________________P") -end - -return PuzzleSquare (DIR) diff --git a/puzzleview.lua b/puzzleview.lua @@ -1,120 +0,0 @@ -local Blitbuffer = require("ffi/blitbuffer") -local Device = require("device") -local Screen = Device.screen -local Size = require("ui/size") -local Geom = require("ui/geometry") -local FrameContainer = require("ui/widget/container/framecontainer") -local InputContainer = require("ui/widget/container/inputcontainer") -local OverlapGroup = require("ui/widget/overlapgroup") -local VerticalGroup = require("ui/widget/verticalgroup") -local HorizontalGroup = require("ui/widget/horizontalgroup") -local logger = require("logger") - -local PuzzleRow = require("puzzlerow") -local PuzzleSquare = require("puzzlesquare") - - -local PuzzleView = InputContainer:new{ - width = nil, - height = nil, - size = { - cols = nil, - rows = nil, - } -} - -function PuzzleView:init() - - -- Temp! This will be the puzzle object, eventually. - local letters = { - {"A","B",".","C","D","E"}, - {"B",".","C","D","E","C"}, - } - - local puzzle_cols = #letters[1] - local puzzle_rows = #letters - - self.dimen = Geom:new{ - w = self.width or Screen:getWidth(), - h = self.height or Screen:getHeight(), - } - self.outer_padding = Size.padding.large - self.inner_padding = Size.padding.small - self.inner_dimen = Geom:new{ - w = self.dimen.w - 2 * self.outer_padding, - h = self.dimen.h - self.outer_padding, -- no bottom padding - } - self.content_width = self.inner_dimen.w - -- The grid dimensions of the puzzle. - --self.grid = { - -- cols = puzzle_cols, - -- rows = puzzle_rows, - --} - -- The pixel dimensions of the squares. Calculate the initial width based on the size - -- of the device and the number of columns. Then make a minor adjustment to account for - -- the margins. To do this, divide margin in 4 and multiply by the number of columns. - self.square_margin = Size.border.window - self.square_width = math.floor( - (self.dimen.w - (2 * self.outer_padding) - (2 * self.inner_padding)) - / self.size.cols) - ((self.square_margin / 4) * (puzzle_cols)) - self.square_height = self.square_width - - ------------------ - -- Add the squares - self.rows_group = VerticalGroup:new{ border = 0 } - - for i, l in ipairs(self.grid) do - table.insert(self.rows_group, self:buildRow(l)) - end - - --------------- - -- Build the container - - self[1] = FrameContainer:new{ - width = self.dimen.w, - height = self.dimen.h, - padding = self.outer_padding, - padding_bottom = 0, - margin = 0, - bordersize = 0, - background = Blitbuffer.COLOR_BLACK, - VerticalGroup:new{ - align = "center", - background = Blitbuffer.COLOR_GRAY, - -- Add the rows vertical group. - self.rows_group, - } - } -end - -function PuzzleView:create() - -end - --- Given a table containing letters, build a row containing --- squares with said letters. -function PuzzleView:buildRow(squares) - local row = PuzzleRow:new{ - width = self.inner_dimen.w, - height = self.square_height, - } - for i, square in ipairs(squares) do - -- This needs a better name. It should be a combination of the user's input, - -- plus also like the square solve thing (hints, etc.) - local solve = { - letter = square.letter, - number = square.number, - } - local square = PuzzleSquare:new{ - width = self.square_width, - height = self.square_height, - margin = self.square_margin, - solve = solve, - } - row:addSquare(square) - end - row:update() - return row -end - -return PuzzleView