diff --git a/sdcard/c480x272/WIDGETS/SoarETX/1/brkcrv.lua b/sdcard/c480x272/WIDGETS/SoarETX/1/brkcrv.lua index 071de00..d8ba7c2 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/1/brkcrv.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/1/brkcrv.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = 0 local gui = libGUI.newGUI() local colors = libGUI.colors diff --git a/sdcard/c480x272/WIDGETS/SoarETX/1/f3k.lua b/sdcard/c480x272/WIDGETS/SoarETX/1/f3k.lua index 7592147..b96ca2a 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/1/f3k.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/1/f3k.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = DBLSIZE local colors = libGUI.colors local activeGUI @@ -40,7 +40,7 @@ local RGT = LCD_W - 18 local TOP = 50 local BOTTOM = LCD_H - 30 local LINE = 60 -local LINE2 = 28 +local LINE2 = 28 local HEIGHT = 42 local HEIGHT2 = 18 local BUTTON_W = 86 @@ -82,7 +82,7 @@ local state -- Current program state local scores = { } -- List of saved scores local taskWindow = 0 -- Task window duration (zero counts up) local launches = -1 -- Number of launches allowed, -1 for unlimited -local taskScores = 0 -- Number of scores in task +local taskScores = 0 -- Number of scores in task local finalScores = false -- Task scores are final local targetType = 0 -- 1. Huge ladder, 2. Poker, 3. "1234", 4. Big ladder, Else: constant time local scoreType -- 1. Best, 2. Last, 3. Make time @@ -111,7 +111,7 @@ local SCORE_FILE = "/LOGS/JF F3K Scores.csv" -- Handle transitions between program states local function GotoState(newState) state = newState - + -- Stop blinking screenTask.timer0.blink = false @@ -126,13 +126,13 @@ local function GotoState(newState) setStickySwitch(LS_FLT_TMR, false) screenTask.labelTimer0.title = "Target:" screenTask.locked = true - + elseif state == STATE_FLYING then setStickySwitch(LS_WIN_TMR, true) setStickySwitch(LS_FLT_TMR, true) screenTask.labelTimer0.title = "Flight:" screenTask.locked = true - + if model.getTimer(0).start > 0 then -- Report the target time playDuration(model.getTimer(0).start, 0) @@ -140,35 +140,35 @@ local function GotoState(newState) -- ... or beep playTone(1760, 100, PLAY_NOW) end - + elseif state == STATE_COMMITTED then -- Call launch height if getLogicalSwitchValue(LS_ALT) then playNumber(getValue("Alt+"), UNIT_METERS) end - - if launches > 0 then + + if launches > 0 then launches = launches - 1 end - + lastChange = 0 - + elseif state == STATE_FINISHED then playTone(880, 1000, 0) end - + -- Configure "button3" screenTask.button3.disabled = false if state <= STATE_PAUSE then - screenTask.button3.title = "Start" + screenTask.button3.title = "Start" elseif state == STATE_WINDOW then screenTask.button3.title = "Pause" elseif state >= STATE_COMMITTED then screenTask.button3.title = "Zero" else - screenTask.button3.disabled = true + screenTask.button3.disabled = true end - + -- Configure info text label if state == STATE_PAUSE then screenTask.labelInfo.title = string.format("Total: %i sec.", totalScore) @@ -188,18 +188,18 @@ end -- GotoState() -- Function for setting up a task local function SetupTask(taskName, taskData) screenTask.title = taskName - + taskWindow = taskData[1] launches = taskData[2] taskScores = taskData[3] finalScores = taskData[4] targetType = taskData[5] scoreType = taskData[6] - screenTask.buttonQR.value = taskData[7] + screenTask.buttonQR.value = taskData[7] scores = { } totalScore = 0 pokerCalled = false - + -- Setup scores for i = 1, N_LINES do if i > taskScores then @@ -210,7 +210,7 @@ local function SetupTask(taskName, taskData) screenTask.scores[i].hidden = false end end - + -- A few extra counts in 1234 if targetType == 3 then counts = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30, 45, 65, 70, 75, 125, 130, 135, 185, 190, 195} @@ -236,7 +236,7 @@ local function RecordBest(scores, newScore) if newScore > scores[i] then j = i end i = i + 1 end - + if j == 0 then j = i end -- New score is smallest; end of the list end @@ -298,7 +298,7 @@ local function Score() end - totalScore = 0 + totalScore = 0 for i = 1, #scores do totalScore = totalScore + math.min(MaxScore(i), scores[i]) end @@ -307,7 +307,7 @@ end -- Score() -- Reset altimeter local function ResetAlt() for i = 0, 31 do - if model.getSensor(i).name == "Alt" then + if model.getSensor(i).name == "Alt" then model.resetSensor(i) break end @@ -370,11 +370,11 @@ end -- Best1234Target(..) -- Get called time from user in Poker local function PokerCall() local dial - + -- Find dials for setting target time in Poker and height ceilings etc. for input = 0, 31 do local tbl = model.getInput(input, 0) - + if tbl and tbl.name == "Dial" then dial = tbl.source end @@ -393,24 +393,24 @@ local function PokerCall() t2 = tblStep[i + 1][1] end local dt = tblStep[i][2] - + local result = t1 + dt * math.floor(x * (t2 - t1) /dt) - + if scoreType == 3 then result = math.min(winTimer - 1, result) end - + if math.abs(input - lastInput) >= 20 then lastInput = input lastChange = getTime() end - + if state == STATE_COMMITTED and lastChange > 0 and getTime() - lastChange > 100 then playTone(3000, 100, PLAY_NOW) playDuration(result) lastChange = 0 end - + return result end -- PokerCall() @@ -435,11 +435,11 @@ local function TargetTime() return MaxScore(#scores + 1) end end -- TargetTime() - + -- Initialize variables before flight local function InitializeFlight() local targetTime = TargetTime() - + -- Get ready to count down countIndex = #counts while countIndex > 1 and counts[countIndex] >= targetTime do @@ -468,7 +468,7 @@ function widget.background() ResetAlt() end - + -- Call altitude every 10 sec. if getLogicalSwitchValue(LS_ALT10) and now > nextCall then playNumber(getValue("Alt"), UNIT_METERS) @@ -478,11 +478,11 @@ function widget.background() if state <= STATE_READY and state ~= STATE_FINISHED then InitializeFlight() end - + flightTimer = model.getTimer(0).value flightTime = math.abs(model.getTimer(0).start - flightTimer) winTimer = model.getTimer(1).value - + if state < STATE_WINDOW then if state == STATE_IDLE then -- Set window timer @@ -515,7 +515,7 @@ function widget.background() -- Play tone to warn that timer is NOT running playTone(1760, 200, 0, PLAY_NOW) end - + elseif state == STATE_READY then if launchReleased then GotoState(STATE_FLYING) @@ -533,12 +533,12 @@ function widget.background() elseif flightTimer > 0 and math.ceil(flightTimer / 60) < math.ceil(prevFt / 60) then playDuration(flightTimer, 0) end - + -- Blink when flight ttimer is negative if flightTimer < 0 then screenTask.timer0.blink = true end - + if state == STATE_FLYING then -- Within 10 sec. "grace period", cancel the flight if launchPulled then @@ -549,7 +549,7 @@ function widget.background() if flightTime >= 10 then GotoState(STATE_COMMITTED) end - + elseif launchPulled then -- Report the time after flight is done if model.getTimer(0).start == 0 then @@ -557,7 +557,7 @@ function widget.background() end Score() - + -- Change state if (finalScores and #scores == taskScores) or launches == 0 or (taskWindow > 0 and winTimer <= 0) then GotoState(STATE_FINISHED) @@ -568,7 +568,7 @@ function widget.background() end end end - + prevWt = winTimer prevFt = flightTimer end @@ -622,12 +622,12 @@ function libGUI.widgetRefresh() local COL2 = COL1 + 30 local COL3 = COL1 + 125 local RGT = COL1 + 400 - + -- Draw scores x = 5 local y = 0 local dy = widget.zone.h / N_LINES - + for i = 1, taskScores do lcd.drawText(COL1, y, string.format("%i.", i), colors.primary1 + DBLSIZE) if i > #scores then @@ -641,14 +641,14 @@ function libGUI.widgetRefresh() -- Draw timers local blink = 0 local y = 4 - + local tmr = model.getTimer(0).value - if tmr < 0 and state == STATE_COMMITTED then + if tmr < 0 and state == STATE_COMMITTED then blink = BLINK end lcd.drawText(COL3, y + 10, screenTask.labelTimer0.title, colors.primary1 + DBLSIZE) - lcd.drawTimer(RGT, y, tmr, colors.primary1 + blink + XXLSIZE + RIGHT) + lcd.drawTimer(RGT, y, tmr, colors.primary1 + blink + XXLSIZE + RIGHT) y = y + 2 * dy tmr = model.getTimer(1).value lcd.drawText(COL3, y + 10, "Task:", colors.primary1 + DBLSIZE) @@ -660,13 +660,13 @@ end -- widgetRefresh() local function SetupScreen(gui, title, pop) gui.title = title local x1 - + if pop then x1 = LCD_W - 80 else x1 = LCD_W - 50 end - + function gui.fullScreenRefresh() local color lcd.clear(COLOR_THEME_SECONDARY3) @@ -678,17 +678,17 @@ local function SetupScreen(gui, title, pop) -- Date local now = getDateTime() local str = string.format("%02i:%02i", now.hour, now.min) - lcd.drawText(x1, 6, str, RIGHT + MIDSIZE + colors.primary2) + lcd.drawText(x1, 6, str, RIGHT + MIDSIZE + colors.primary2) if soarGlobals.battery == 0 then color = COLOR_THEME_DISABLED else color = colors.primary2 end - + str = string.format("%1.1fV", soarGlobals.battery) lcd.drawText(x1 - 65, 6, str, RIGHT + MIDSIZE + color) - + -- Draw trims local p = { { LCD_W - 191, LCD_H - 14, 177, 8 }, @@ -696,7 +696,7 @@ local function SetupScreen(gui, title, pop) { LCD_W - 14, 68, 8, 177 }, { 7, 68, 8, 177 }, } - + for i = 1, 4 do local q = p[i] local value = getValue(trimSources[i]) / 10.24 @@ -708,21 +708,21 @@ local function SetupScreen(gui, title, pop) x = q[1] + q[3] / 2 y = q[2] + q[4] * (100 - value) / 200 end - + lcd.drawFilledRectangle(q[1], q[2], q[3], q[4], COLOR_THEME_SECONDARY1) lcd.drawFilledRectangle(x - 9, y - 6, 18, 15, colors.primary1) lcd.drawFilledRectangle(x - 10, y - 7, 18, 15, colors.focus) lcd.drawNumber(x, y, value, SMLSIZE + VCENTER + CENTER + colors.primary2) end - + -- Flight mode - lcd.drawText(LCD_W / 2, LCD_H - LINE2, select(2, getFlightMode()), MIDSIZE + CENTER + COLOR_THEME_SECONDARY1) + lcd.drawText(LCD_W / 2, LCD_H - LINE2, select(2, getFlightMode()), MIDSIZE + CENTER + COLOR_THEME_SECONDARY1) end -- fullScreenRefresh() - + -- Return button if pop then gui.buttonRet = gui.custom({ }, LCD_W - 74, 6, 28, 28) - + function gui.buttonRet.draw(focused) local color @@ -733,14 +733,14 @@ local function SetupScreen(gui, title, pop) color = COLOR_THEME_DISABLED gui.buttonRet.disabled = true end - + lcd.drawRectangle(LCD_W - 74, 6, 28, 28, color) lcd.drawFilledRectangle(LCD_W - 61, 12, 3, 18, color) for i = 0, 3 do lcd.drawLine(LCD_W - 60 , 10 + i, LCD_W - 50 - i, 20, SOLID, color) lcd.drawLine(LCD_W - 60 , 10 + i, LCD_W - 70 + i, 20, SOLID, color) end - + if focused then gui.buttonRet.drawFocus() end @@ -752,7 +752,7 @@ local function SetupScreen(gui, title, pop) end end end - + -- Minimize button local buttonMin = gui.custom({ }, LCD_W - 34, 6, 28, 28) @@ -764,7 +764,7 @@ local function SetupScreen(gui, title, pop) buttonMin.drawFocus() end end - + function buttonMin.onEvent(event) if event == EVT_VIRTUAL_ENTER then lcd.exitFullScreen() @@ -780,7 +780,7 @@ local function SetupScreen(gui, title, pop) end end gui.setEventHandler(EVT_VIRTUAL_EXIT, HandleEXIT) - + return gui end -- SetupScreen @@ -791,7 +791,7 @@ do local ROW = 65 x = 40 y = 60 - + SetupScreen(menuMain, "SoarETX F3K") -- Generate callbacks with closure for calling submenus @@ -806,7 +806,7 @@ do menuMain.button(x, y, WIDTH, HEIGHT, "Practice", MakePush(menuPractice)) y = y + ROW menuMain.button(x, y, WIDTH, HEIGHT, "Scores", MakePush(menuScores)) - + activeGUI = menuMain end @@ -831,7 +831,7 @@ do -- Setup F3K tasks menu "L. One flight only", "M. Huge Ladder" } - + -- {win, launches, scores, final, tgtType, scoType, QR } local taskData = { { 420, -1, 1, false, 300, 2, false }, -- A. Last flight @@ -862,7 +862,7 @@ end do -- Setup practice tasks menu SetupScreen(menuPractice, "Practice Tasks", true) - + local tasks = { "Just Fly!", "Quick Relaunch!", @@ -875,7 +875,7 @@ do -- Setup practice tasks menu { 0, -1, 5, false, 2, 2, true }, -- QR { 600, 2, 2, true, 5, 2, false } -- Deuces } - + -- Call back function running when a menu item is selected local function callBack(menu) SetupTask(tasks[menu.selected], taskData[menu.selected]) @@ -888,13 +888,13 @@ end do -- Setup score keeper screen for F3K and Practice tasks SetupScreen(screenTask, "", true) - + -- Restore default task and dismiss task screen - function screenTask.dismiss() + function screenTask.dismiss() SetupTask("Just Fly!", { 0, -1, 5, false, 0, 2, false }) PopGUI() end - + -- Return button shows prompt to save scores instead of popping right away function screenTask.buttonRet.onEvent(event) if event == EVT_VIRTUAL_ENTER then @@ -905,17 +905,17 @@ do -- Setup score keeper screen for F3K and Practice tasks end end end - + -- Add score times local y = TOP local dy = select(2, lcd.sizeText("", libGUI.flags)) - + screenTask.scoreLabels = { } screenTask.scores = { } for i = 1, N_LINES do screenTask.scoreLabels[i] = screenTask.label(LEFT, y, 20, HEIGHT, string.format("%i.", i)) - + local s = screenTask.timer(LEFT + 40, y, 60, HEIGHT, 0, nil) s.disabled = true s.value = "- - -" @@ -924,35 +924,35 @@ do -- Setup score keeper screen for F3K and Practice tasks -- Modify timer's draw function to insert score value local draw = s.draw function s.draw(idx) - if i > #scores then + if i > #scores then screenTask.scores[i].value = "- - -" else screenTask.scores[i].value = scores[i] end - + draw(idx) end y = y + dy end - + -- Add center buttons local y = TOP screenTask.buttonQR = screenTask.toggleButton(COL2, y, BUTTON_W, HEIGHT, "QR", false, nil) y = y + LINE screenTask.buttonEoW = screenTask.toggleButton(COL2, y, BUTTON_W, HEIGHT, "EoW", true, nil) - + local function callBack(button) if state <= STATE_PAUSE then GotoState(STATE_WINDOW) - + elseif state == STATE_WINDOW then GotoState(STATE_PAUSE) - + elseif state >= STATE_COMMITTED then -- Record a zero score! flightTime = 0 Score() - + -- Change state if winTimer <= 0 or (finalScores and #scores == taskScores) or launches == 0 then GotoState(STATE_FINISHED) @@ -962,26 +962,26 @@ do -- Setup score keeper screen for F3K and Practice tasks end end end - + y = y + LINE screenTask.button3 = screenTask.button(COL2, y, BUTTON_W, HEIGHT, "Start", callBack) - + -- Info text label screenTask.labelInfo = screenTask.label(RGT - 250, BOT_ROW, 250, HEIGHT, "", libGUI.flags + RIGHT) - + -- Add timers y = TOP screenTask.labelTimer0 = screenTask.label(RGT - 160, y, 50, HEIGHT2, "Target:", MIDSIZE) y = y + LINE2 screenTask.timer0 = screenTask.timer(RGT - 160, y, 160, HEIGHT, 0, nil, XXLSIZE + RIGHT) screenTask.timer0.disabled = true - + y = y + LINE screenTask.label(RGT - 160, y, 50, HEIGHT2, "Task:", MIDSIZE) y = y + LINE2 local tmr = screenTask.timer(RGT - 160, y, 160, HEIGHT, 1, nil, XXLSIZE + RIGHT) tmr.disabled = true - + -- Short press EXIT handler must prompt to save scores local function HandleEXIT(event, touchState) if CanPopGUI() then @@ -1001,7 +1001,7 @@ do -- Prompt asking to save scores and exit task window local RGT = x0 + PROMPT_W - PROMPT_M local TOP = y0 + PROMPT_M local BOTTOM = y0 + PROMPT_H - PROMPT_M - + function promptSaveScores.fullScreenRefresh() lcd.drawFilledRectangle(x0, y0, PROMPT_W, PROMPT_H, colors.primary2) lcd.drawRectangle(x0, y0, PROMPT_W, PROMPT_H, colors.primary1, 3) @@ -1015,21 +1015,21 @@ do -- Prompt asking to save scores and exit task window if scoreFile then io.write(scoreFile, string.format("%s,%s", model.getInfo().name, screenTask.title)) - local now = getDateTime() + local now = getDateTime() io.write(scoreFile, string.format(",%04i-%02i-%02i", now.year, now.mon, now.day)) - io.write(scoreFile, string.format(",%02i:%02i", now.hour, now.min)) + io.write(scoreFile, string.format(",%02i:%02i", now.hour, now.min)) io.write(scoreFile, string.format(",s,%i", taskScores)) io.write(scoreFile, string.format(",%i", totalScore)) - + for i = 1, #scores do io.write(scoreFile, string.format(",%i", scores[i])) end - + io.write(scoreFile, "\n") io.close(scoreFile) end end - + -- Dismiss prompt and return to menu screenTask.dismissPrompt() screenTask.dismiss() @@ -1047,7 +1047,7 @@ do -- Setup score browser screen local scoreFile -- File handle local pos -- Read position in file local firstRecordTouch -- First record at the start of touch slide - + -- Read a line of a log file local function ReadLine(scoreFile, pos) if scoreFile and pos then @@ -1061,7 +1061,7 @@ do -- Setup score browser screen return pos, str end end - + -- No "\n" was found; return nothing return 0, "" end -- ReadLine() @@ -1074,7 +1074,7 @@ do -- Setup score browser screen for field in string.gmatch(str, "[^,]+") do i = i + 1 - + if i == 1 then record.planeName = field elseif i == 2 then @@ -1093,33 +1093,33 @@ do -- Setup score browser screen record.scores[#record.scores + 1] = tonumber(field) end end - + if record.totalScore then records[#records + 1] = record end end -- ReadLineData() - + local function DrawRecord(i, r) local top = 40 + i * RECORD_H local left = 200 local w = (LCD_W - left - 10) / 3 local record = records[r] - + if not record then return end - + if r % 2 == 0 then lcd.drawFilledRectangle(0, top, LCD_W, RECORD_H, COLOR_THEME_SECONDARY2) end - + lcd.drawText(10, top + 6, record.taskName, BOLD) lcd.drawText(10, top + 24, record.dateStr .. " " .. record.timeStr, SMLSIZE) lcd.drawText(10, top + 36, record.planeName, SMLSIZE) - + local x = left local y = top + 6 - + for j = 1, math.min(5, record.taskScores) do lcd.drawText(x, y, j .. ".") @@ -1130,7 +1130,7 @@ do -- Setup score browser screen else lcd.drawText(x + 18, y, record.scores[j] .. record.unitStr) end - + if j == 3 then x = left y = top + 30 @@ -1138,7 +1138,7 @@ do -- Setup score browser screen x = x + w end end - + lcd.drawText(left + 2 * w, top + 30, "Total: " .. record.totalScore .. record.unitStr) end -- DrawRecord @@ -1152,7 +1152,7 @@ do -- Setup score browser screen end lcd.clear(COLOR_THEME_SECONDARY3) - + -- Top bar lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) lcd.drawText(10, 2, "Score Card", bit32.bor(DBLSIZE, colors.primary2)) @@ -1160,25 +1160,25 @@ do -- Setup score browser screen -- Date local now = getDateTime() local str = string.format("%02i:%02i", now.hour, now.min) - lcd.drawText(LCD_W - 80, 6, str, RIGHT + MIDSIZE + colors.primary2) + lcd.drawText(LCD_W - 80, 6, str, RIGHT + MIDSIZE + colors.primary2) if soarGlobals.battery == 0 then color = COLOR_THEME_DISABLED else color = colors.primary2 end - + str = string.format("%1.1fV", soarGlobals.battery) lcd.drawText(LCD_W - 140, 6, str, RIGHT + MIDSIZE + color) - + -- Return button lcd.drawFilledRectangle(LCD_W - 74, 6, 28, 28, COLOR_THEME_SECONDARY1) lcd.drawRectangle(LCD_W - 74, 6, 28, 28, colors.primary2) - + for i = -1, 1 do lcd.drawLine(LCD_W - 60 + i, 12, LCD_W - 60 + i, 30, SOLID, colors.primary2) end - + for i = 0, 3 do lcd.drawLine(LCD_W - 60 , 10 + i, LCD_W - 50 - i, 20, SOLID, colors.primary2) lcd.drawLine(LCD_W - 60 , 10 + i, LCD_W - 70 + i, 20, SOLID, colors.primary2) @@ -1188,17 +1188,17 @@ do -- Setup score browser screen lcd.drawFilledRectangle(LCD_W - 34, 6, 28, 28, COLOR_THEME_SECONDARY1) lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) lcd.drawFilledRectangle(LCD_W - 30, 19, 20, 3, colors.primary2) - + if event ~= EVT_TOUCH_SLIDE then firstRecordTouch = nil end - + if event == EVT_VIRTUAL_EXIT then firstRecord = nil return PopGUI() elseif event == EVT_TOUCH_TAP then local x, y = touchState.x, touchState.y - + if 6 <= y and y <= 34 then if LCD_W - 74 <= x and x <= LCD_W - 40 then firstRecord = nil @@ -1226,9 +1226,9 @@ do -- Setup score browser screen local r = i + firstRecord DrawRecord(i, r) end - + else -- Read score records - lcd.drawText(LCD_W / 2, LCD_H / 2, "Reading scores ...", VCENTER + CENTER + DBLSIZE + colors.primary1) + lcd.drawText(LCD_W / 2, LCD_H / 2, "Reading scores ...", VCENTER + CENTER + DBLSIZE + colors.primary1) if not scoreFile then scoreFile = io.open(SCORE_FILE, "r") @@ -1237,7 +1237,7 @@ do -- Setup score browser screen records = { } end end - + if scoreFile then for i = 1, 10 do local str @@ -1247,11 +1247,11 @@ do -- Setup score browser screen io.close(scoreFile) scoreFile = nil firstRecord = math.max(1, #records - 3) - + if #records == 0 then firstRecord = nil end - + break end end diff --git a/sdcard/c480x272/WIDGETS/SoarETX/1/f3k_ctr.lua b/sdcard/c480x272/WIDGETS/SoarETX/1/f3k_ctr.lua index 510ee94..2c7c49a 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/1/f3k_ctr.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/1/f3k_ctr.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = 0 local gui = libGUI.newGUI() local colors = libGUI.colors @@ -84,9 +84,9 @@ end local function adjust(slider) -- Compensate for possible negative differential local dif = model.getGlobalVariable(GV_DIF, 0) - local difComp = 100.0 / math.max(10.0, math.min(100.0, 100.0 + dif)) + local difComp = 100.0 / math.max(10.0, math.min(100.0, 100.0 + dif)) -- Calculate aileron travel from current airbrake travel - local ail = math.min(2 * slider.value, 2 * (100 - slider.value) * difComp) + local ail = math.min(2 * slider.value, 2 * (100 - slider.value) * difComp) model.setGlobalVariable(GV_AIL, 0, ail) model.setGlobalVariable(GV_BRK, 0, slider.value) end @@ -96,7 +96,7 @@ end do function gui.fullScreenRefresh() lcd.clear(COLOR_THEME_SECONDARY3) - + -- Top bar lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) lcd.drawText(10, 2, title, bit32.bor(DBLSIZE, colors.primary2)) @@ -107,12 +107,12 @@ do local brk = 2 * model.getGlobalVariable(GV_BRK, 0) local brkDeg = 0.45 * brk local dif = 0.01 * model.getGlobalVariable(GV_DIF, 0) - + lcd.drawPie(CTR_X, CTR_Y, R2, 90 - ailDeg * math.min(1, 1 + dif), 91 + brkDeg, colors.primary2) lcd.drawAnnulus(CTR_X, CTR_Y, R1, R2, 90 + ailDeg * math.min(1, 1 - dif), 90 + brkDeg, COLOR_THEME_SECONDARY2) lcd.drawAnnulus(CTR_X, CTR_Y, R1, R2, 90, 90 + ailDeg * math.min(1, 1 - dif), COLOR_BLEND) lcd.drawAnnulus(CTR_X, CTR_Y, R1, R2, 90 - ailDeg * math.min(1, 1 + dif), 90, COLOR_THEME_SECONDARY1) - + lcd.drawArc(CTR_X, CTR_Y, R2, 90 - ailDeg * math.min(1, 1 + dif), 90 + brkDeg, colors.primary3) drawRadian(90 - ailDeg * math.min(1, 1 + dif)) drawRadian(90) @@ -132,7 +132,7 @@ do lcd.drawText(CTR_X + R1, CTR_Y, "brake ", RIGHT + SMLSIZE + colors.primary1) lcd.drawText(CTR_X + R2, CTR_Y - SML_H, " max.", SMLSIZE + colors.primary1) lcd.drawText(CTR_X + R2, CTR_Y, " reflex", SMLSIZE + colors.primary1) - + local txt = "Use the slider to adjust the flaperons to the position of maximum reflex.\n\n" .. "Notice that camber can only move the flaperons down from this position." lcd.drawTextLines(MARGIN, TOP, CTR_X - 2 * MARGIN, LCD_H - TOP - MARGIN, txt, colors.primary1) @@ -178,6 +178,6 @@ function widget.refresh(event, touchState) setStickySwitch(LS_CTR, true) slider.value = model.getGlobalVariable(GV_BRK, 0) end - + gui.run(event, touchState) end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/1/f3k_mix.lua b/sdcard/c480x272/WIDGETS/SoarETX/1/f3k_mix.lua index fd8f290..275c42d 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/1/f3k_mix.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/1/f3k_mix.lua @@ -20,7 +20,8 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +print(string.format("111 f3k_mix soarGlobals.libGUI: [%s]", soarGlobals.libGUI)) +local libGUI = soarGlobals.libGUI libGUI.flags = 0 local gui = libGUI.newGUI() local colors = libGUI.colors @@ -41,23 +42,23 @@ local W2 = LCD_W2 - 2 * MARGIN - W1 do function gui.fullScreenRefresh() lcd.clear(COLOR_THEME_SECONDARY3) - + -- Top bar lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) lcd.drawText(10, 2, title, bit32.bor(DBLSIZE, colors.primary2)) - + -- Fligh mode local fmIdx, fmStr = getFlightMode() lcd.drawText(LCD_W - HEADER, HEADER / 2, "FM" .. fmIdx .. ":" .. fmStr, RIGHT + VCENTER + MIDSIZE + colors.primary2) - + -- Line stripes for i = 1, 3, 2 do lcd.drawFilledRectangle(0, HEADER + LINE * i, LCD_W, LINE, COLOR_THEME_SECONDARY2) end - + local bottom = HEADER + 4 * LINE lcd.drawLine(LCD_W2, HEADER, LCD_W2, bottom, SOLID, colors.primary1) - + -- Help text local txt = "Some variables can be adjusted individually for each flight mode.\n" .. "Therefore, select the flight mode for which you want to adjust.\n" .. @@ -85,7 +86,7 @@ do -- Grid for items local x, y = MARGIN, HEADER + 2 - + local function move() if x == MARGIN then x = x + LCD_W2 @@ -94,11 +95,11 @@ do y = y + LINE end end - + -- Add label and number element for a GV local function addGV(label, gv, min, max) gui.label(x, y, W1, HEIGHT, label) - + local function changeGV(delta, number) local value = number.value + delta value = math.max(value, min) @@ -106,16 +107,16 @@ do model.setGlobalVariable(gv, fm, value) return value end - + local number = gui.number(x + W1, y, W2, HEIGHT, 0, changeGV, RIGHT + libGUI.flags) - + function number.update() number.value = model.getGlobalVariable(gv, fm) end - + move() end - + -- ADD GVs addGV("Aileron " .. CHAR_RIGHT .. " rudder", 2, -100, 100) addGV("Differential", 3, -100, 100) @@ -124,7 +125,7 @@ do addGV("Elevator input", 6, 20, 100) addGV("Aileron input", 7, 20, 100) addGV("Exponential", 8, 20, 100) - + -- Add battery warning gui.label(x, y, W1, HEIGHT, "Battery warning level (V)") @@ -135,7 +136,7 @@ do soarGlobals.setParameter(soarGlobals.batteryParameter, value - 100) return value end - + local batP = soarGlobals.getParameter(soarGlobals.batteryParameter) gui.number(x + W1, y, W2, HEIGHT, batP + 100, changeBattery, RIGHT + PREC1 + libGUI.flags) end -- Setup GUI @@ -150,8 +151,8 @@ function widget.refresh(event, touchState) lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) return end - + fm = getFlightMode() - + gui.run(event, touchState) end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/1/f3k_sw.lua b/sdcard/c480x272/WIDGETS/SoarETX/1/f3k_sw.lua index 5e2afbe..a2f62a8 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/1/f3k_sw.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/1/f3k_sw.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = 0 local gui local colors = libGUI.colors @@ -50,7 +50,7 @@ local items = { local function init() gui = libGUI.newGUI() - + function gui.fullScreenRefresh() -- Top bar lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) @@ -88,7 +88,7 @@ local function init() -- Build the list of drop downs local y = HEADER + 2 local w1 = COL2 - MARGIN - + -- Build lists of physical switch position indices and names local swIndices = { } local swNames = { } @@ -107,20 +107,20 @@ local function init() lsTbl.v1 = swIdx model.setLogicalSwitch(dropDown.ls, lsTbl) end - + for i, item in ipairs(items) do gui.label(MARGIN, y, w1, HEIGHT, item[1]) - + local swIdx = model.getLogicalSwitch(item[2]).v1 local selected = 0 - + for i, idx in ipairs(swIndices) do if swIdx == idx then selected = i break end end - + if selected == 0 then -- Oops, no switch matching current value in LS! gui.label(COL2, y, WIDTH, HEIGHT, "???", CENTER + BOLD) @@ -148,6 +148,6 @@ function widget.refresh(event, touchState) init() return end - + gui.run(event, touchState) end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/1/f3kfh_mx.lua b/sdcard/c480x272/WIDGETS/SoarETX/1/f3kfh_mx.lua index c856843..0bed2a1 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/1/f3kfh_mx.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/1/f3kfh_mx.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = 0 local gui = libGUI.newGUI() local colors = libGUI.colors diff --git a/sdcard/c480x272/WIDGETS/SoarETX/1/f3kre_mx.lua b/sdcard/c480x272/WIDGETS/SoarETX/1/f3kre_mx.lua index 49aefeb..5fee420 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/1/f3kre_mx.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/1/f3kre_mx.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = 0 local gui = libGUI.newGUI() local colors = libGUI.colors @@ -41,23 +41,23 @@ local W2 = LCD_W2 - 2 * MARGIN - W1 do function gui.fullScreenRefresh() lcd.clear(COLOR_THEME_SECONDARY3) - + -- Top bar lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) lcd.drawText(10, 2, title, bit32.bor(DBLSIZE, colors.primary2)) - + -- Fligh mode local fmIdx, fmStr = getFlightMode() lcd.drawText(LCD_W - HEADER, HEADER / 2, "FM" .. fmIdx .. ":" .. fmStr, RIGHT + VCENTER + MIDSIZE + colors.primary2) - + -- Line stripes for i = 1, 3, 2 do lcd.drawFilledRectangle(0, HEADER + LINE * i, LCD_W, LINE, COLOR_THEME_SECONDARY2) end - + local bottom = HEADER + 4 * LINE lcd.drawLine(LCD_W2, HEADER, LCD_W2, bottom, SOLID, colors.primary1) - + -- Help text local txt = "Some variables can be adjusted individually for each flight mode.\n" .. "Therefore, select the flight mode for which you want to adjust.\n" .. @@ -85,7 +85,7 @@ do -- Grid for items local x, y = MARGIN, HEADER + 2 - + local function move() if x == MARGIN then x = x + LCD_W2 @@ -94,11 +94,11 @@ do y = y + LINE end end - + -- Add label and number element for a GV local function addGV(label, gv, min, max) gui.label(x, y, W1, HEIGHT, label) - + local function changeGV(delta, number) local value = number.value + delta value = math.max(value, min) @@ -106,20 +106,20 @@ do model.setGlobalVariable(gv, fm, value) return value end - + local number = gui.number(x + W1, y, W2, HEIGHT, 0, changeGV, RIGHT + libGUI.flags) - + function number.update() number.value = model.getGlobalVariable(gv, fm) end - + move() end - + -- ADD GVs addGV("Elevator input", 6, 20, 100) addGV("Exponential", 8, 20, 100) - + -- Add battery warning gui.label(x, y, W1, HEIGHT, "Battery warning level (V)") @@ -130,7 +130,7 @@ do soarGlobals.setParameter(soarGlobals.batteryParameter, value - 100) return value end - + local batP = soarGlobals.getParameter(soarGlobals.batteryParameter) gui.number(x + W1, y, W2, HEIGHT, batP + 100, changeBattery, RIGHT + PREC1 + libGUI.flags) end -- Setup GUI @@ -145,8 +145,8 @@ function widget.refresh(event, touchState) lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) return end - + fm = getFlightMode() - + gui.run(event, touchState) end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/1/f3kre_sw.lua b/sdcard/c480x272/WIDGETS/SoarETX/1/f3kre_sw.lua index a62e2c2..235a905 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/1/f3kre_sw.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/1/f3kre_sw.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = 0 local gui local colors = libGUI.colors @@ -49,7 +49,7 @@ local items = { local function init() gui = libGUI.newGUI() - + function gui.fullScreenRefresh() -- Top bar lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) @@ -87,11 +87,11 @@ local function init() -- Build the list of drop downs local y = HEADER + 2 local w1 = COL2 - MARGIN - + -- Build lists of physical switch position indices and names local swIndices = { } local swNames = { } - + for swIdx, swName in switches() do if string.find(swName,"^!?S[A-H][+-]?") then i = #swIndices + 1 @@ -106,20 +106,20 @@ local function init() lsTbl.v1 = swIdx model.setLogicalSwitch(dropDown.ls, lsTbl) end - + for i, item in ipairs(items) do gui.label(MARGIN, y, w1, HEIGHT, item[1]) - + local swIdx = model.getLogicalSwitch(item[2]).v1 local selected = 0 - + for i, idx in ipairs(swIndices) do if swIdx == idx then selected = i break end end - + if selected == 0 then -- Oops, no switch matching current value in LS! gui.label(COL2, y, WIDTH, HEIGHT, "???", CENTER + BOLD) @@ -147,6 +147,6 @@ function widget.refresh(event, touchState) init() return end - + gui.run(event, touchState) end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/1/graph.lua b/sdcard/c480x272/WIDGETS/SoarETX/1/graph.lua index 97bdc70..95225a0 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/1/graph.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/1/graph.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = 0 local colors = libGUI.colors local title = "Graph" diff --git a/sdcard/c480x272/WIDGETS/SoarETX/1/outputs.lua b/sdcard/c480x272/WIDGETS/SoarETX/1/outputs.lua index b56b33a..4ff0f7b 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/1/outputs.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/1/outputs.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = MIDSIZE local gui local colors = libGUI.colors @@ -75,12 +75,12 @@ do local PROMPT_H = 172 warningPrompt.x = (LCD_W - PROMPT_W) / 2 warningPrompt.y = (LCD_H - PROMPT_H) / 2 - + function warningPrompt.fullScreenRefresh() local txt = "Please disable the motor!\n\n" .. "Sudden spikes may occur when channels are moved.\n\n" .. "Press ENTER to proceed." - + warningPrompt.drawFilledRectangle(0, 0, PROMPT_W, HEADER, COLOR_THEME_SECONDARY1) warningPrompt.drawFilledRectangle(0, HEADER, PROMPT_W, PROMPT_H - HEADER, libGUI.colors.primary2) warningPrompt.drawRectangle(0, 0, PROMPT_W, PROMPT_H, libGUI.colors.primary1, 2) @@ -125,7 +125,7 @@ do } editPrompt.x = (LCD_W - PROMPT_W) / 2 editPrompt.y = (LCD_H - PROMPT_H) / 2 - + function editPrompt.fullScreenRefresh() if not editPrompt.editing then editPoints = 0 @@ -138,7 +138,7 @@ do editPrompt.drawFilledRectangle(0, HEADER, PROMPT_W, PROMPT_H - HEADER, libGUI.colors.primary2) editPrompt.drawRectangle(0, 0, PROMPT_W, PROMPT_H, libGUI.colors.primary1, 2) editPrompt.drawText(MARGIN, HEADER / 2, "Select what to edit:", DBLSIZE + VCENTER + libGUI.colors.primary2) - + local y = HEADER + MARGIN + h / 2 for i = 1, 5 do @@ -162,7 +162,7 @@ do editPoints = menu.selected gui.dismissPrompt() end -- onMenu(...) - + editPrompt.menu(MARGIN, HEADER + MARGIN, MENU_W, MENU_H, menuItems, onMenu) end -- Prompt for selecting what to edit @@ -171,13 +171,13 @@ local function MoveOutput(direction, channel) local m = { } -- Channel indices m[1] = channel.iChannel -- Channel to move m[2] = m[1] + direction -- Neighbouring channel to swap - + -- Are we at then end? if m[2] < 1 or m[2] > N then playTone(3000, 100, 0, PLAY_NOW) return end - + local outputs = { } -- List of output tables local mixes = { } -- List of lists of mixer tables @@ -191,7 +191,7 @@ local function MoveOutput(direction, channel) mixes[i][j] = model.getMix(m[i] - 1, j - 1) end end - + -- Write back swapped data for i = 1, 2 do model.setOutput(m[i] - 1, outputs[3 - i]) @@ -223,7 +223,7 @@ local function MoveOutput(direction, channel) mixes[j].source = m[1] + CHAN_BASE end end - + -- Do we have to write back data? if dirty then -- Delete existing mixer lines @@ -262,7 +262,7 @@ local function init() -- Top bar lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) lcd.drawText(MARGIN, HEADER / 2 - 2, "Configure outputs", DBLSIZE + VCENTER + colors.primary2) - + -- Row background for i = 0, 6 do local y = HEADER + i * ROW @@ -272,7 +272,7 @@ local function init() lcd.drawFilledRectangle(0, y, LCD_W, ROW, COLOR_THEME_SECONDARY3) end end - + -- Adjust scroll for channels if focusNamed > 0 then if focusNamed < firstLine then @@ -282,7 +282,7 @@ local function init() end end focusNamed = 0 - + -- Draw vertical reference lines for i = -6, 6 do local x = CTR - i * MAXOUT / (SCALE * 6) + 2 @@ -313,10 +313,10 @@ local function init() local HEIGHT = ROW - 8 local iNamed = 0 channels = { } - + for iChannel = 1, N do local output = model.getOutput(iChannel - 1) - + if output and output.name ~= "" then local channel = gui.gui(2, LCD_H, LCD_W - 4, ROW - 4) local d0 @@ -356,8 +356,8 @@ local function init() end -- onEvent(...) -- Custom element for changing output channel (and moving all mixer lines etc.) - local nbrChannel = channel.custom({ }, 2, 2, 30, HEIGHT) - + local nbrChannel = channel.custom({ }, 2, 2, 30, HEIGHT) + function nbrChannel.draw(focused) local fg = libGUI.colors.primary1 if focused then @@ -391,13 +391,13 @@ local function init() channel.editing = true end end -- onEvent(...) - + -- Label for channel name local lblName = channel.label(32, 2, 140, HEIGHT, ". " .. channel.output.name) - + -- Custom element to invert output direction local revert = channel.custom({ }, 172, 2, 30, HEIGHT) - + function revert.draw(focused) local y = HEIGHT / 2 + 3 if channel.output.revert == 1 then @@ -413,7 +413,7 @@ local function init() channel.drawLine(x, y, x - 8, y + 8, SOLID, colors.primary1) end end - + function revert.onEvent(event, touchState) if event == EVT_VIRTUAL_ENTER then channel.output.revert = 1 - channel.output.revert @@ -435,14 +435,14 @@ local function init() local y = HEIGHT / 2 + 2 local yLbl = y - 12 - select(2, lcd.sizeText("", flags)) local iScroll = 0 - + function interval.draw(focused) local output = channel.output local p = { 0, 0, 0 } local colorBar = libGUI.colors.primary3 local colorDot = libGUI.colors.primary2 local colorDotBorder = libGUI.colors.primary3 - + x = { CTR + output.min / SCALE, CTR + output.offset / SCALE, @@ -457,7 +457,7 @@ local function init() channel.drawNumber(x[3], yLbl, 0.1 * output.max, flags) colorBar = libGUI.colors.primary1 colorDot = libGUI.colors.edit - p = activePoints(editPoints) + p = activePoints(editPoints) else interval.drawFocus() end @@ -477,21 +477,21 @@ local function init() -- Draw position indicators local outX = getValue(CHAN_BASE + channel.iChannel) if outX >= 0 then - outX = output.offset + math.min(outX, 1024) * (output.max - output.offset) / 1024 + outX = output.offset + math.min(outX, 1024) * (output.max - output.offset) / 1024 else - outX = output.offset + math.max(outX, -1024) * (output.offset - output.min) / 1024 + outX = output.offset + math.max(outX, -1024) * (output.offset - output.min) / 1024 end outX = CTR + outX / SCALE channel.drawFilledTriangle(outX, y - 3, outX - 3, y - 9, outX + 3, y - 9, colorBar) channel.drawLine(outX, y - 2, outX, y + 2, SOLID, colorBar) channel.drawFilledTriangle(outX, y + 3, outX - 3, y + 9, outX + 3, y + 9, colorBar) end -- draw(...) - + local RR = 14 ^ 2 - + local function ptCovers(p, q) local ap = activePoints(editPoints) - + for i = 1, 3 do if ap[i] ~= 0 and (x[i] - p) ^ 2 + (y - q) ^ 2 <= RR then return i @@ -499,46 +499,46 @@ local function init() end return 0 end -- ptCovers(...) - + local function adjustPoints(d) local output = channel.output local p = activePoints(editPoints) local min = output.min local ctr = output.offset local max = output.max - + -- Check limits if p[1] == -1 then d = math.min(d, math.max(0, MAXOUT + min)) elseif p[1] == 1 then d = math.max(d, math.min(0, -(MAXOUT + min))) end - + if p[2] - p[1] == 1 then d = math.max(d, math.min(0, MINDIF + min - ctr)) elseif p[2] - p[1] == -1 then d = math.min(d, math.max(0, ctr - min - MINDIF)) end - + if p[3] - p[2] == 1 then d = math.max(d, math.min(0, MINDIF + ctr - max)) elseif p[3] - p[2] == -1 then d = math.min(d, math.max(0, max - ctr - MINDIF)) end - + if p[3] == 1 then d = math.min(d, math.max(0, MAXOUT - max)) end - + -- Update output values output.min = min + p[1] * d output.offset = ctr + p[2] * d output.max = max + p[3] * d - + -- Write back data model.setOutput(channel.iChannel - 1, output) end - + function interval.onEvent(event, touchState) if event == EVT_VIRTUAL_ENTER and not channel.editing then channel.editing = true @@ -586,7 +586,7 @@ function widget.refresh(event, touchState) init() return end - + gui.run(event, touchState) end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/1/wing2.lua b/sdcard/c480x272/WIDGETS/SoarETX/1/wing2.lua index 1526c14..18b4e77 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/1/wing2.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/1/wing2.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = MIDSIZE local gui = libGUI.newGUI() local colors = libGUI.colors diff --git a/sdcard/c480x272/WIDGETS/SoarETX/1/wing4.lua b/sdcard/c480x272/WIDGETS/SoarETX/1/wing4.lua index db35e1a..29f1853 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/1/wing4.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/1/wing4.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = MIDSIZE local gui = libGUI.newGUI() local colors = libGUI.colors diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/ailctr.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/ailctr.lua index 510ee94..1bc4369 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/2/ailctr.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/ailctr.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = 0 local gui = libGUI.newGUI() local colors = libGUI.colors @@ -84,9 +84,9 @@ end local function adjust(slider) -- Compensate for possible negative differential local dif = model.getGlobalVariable(GV_DIF, 0) - local difComp = 100.0 / math.max(10.0, math.min(100.0, 100.0 + dif)) + local difComp = 100.0 / math.max(10.0, math.min(100.0, 100.0 + dif)) -- Calculate aileron travel from current airbrake travel - local ail = math.min(2 * slider.value, 2 * (100 - slider.value) * difComp) + local ail = math.min(2 * slider.value, 2 * (100 - slider.value) * difComp) model.setGlobalVariable(GV_AIL, 0, ail) model.setGlobalVariable(GV_BRK, 0, slider.value) end @@ -96,7 +96,7 @@ end do function gui.fullScreenRefresh() lcd.clear(COLOR_THEME_SECONDARY3) - + -- Top bar lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) lcd.drawText(10, 2, title, bit32.bor(DBLSIZE, colors.primary2)) @@ -107,12 +107,12 @@ do local brk = 2 * model.getGlobalVariable(GV_BRK, 0) local brkDeg = 0.45 * brk local dif = 0.01 * model.getGlobalVariable(GV_DIF, 0) - + lcd.drawPie(CTR_X, CTR_Y, R2, 90 - ailDeg * math.min(1, 1 + dif), 91 + brkDeg, colors.primary2) lcd.drawAnnulus(CTR_X, CTR_Y, R1, R2, 90 + ailDeg * math.min(1, 1 - dif), 90 + brkDeg, COLOR_THEME_SECONDARY2) lcd.drawAnnulus(CTR_X, CTR_Y, R1, R2, 90, 90 + ailDeg * math.min(1, 1 - dif), COLOR_BLEND) lcd.drawAnnulus(CTR_X, CTR_Y, R1, R2, 90 - ailDeg * math.min(1, 1 + dif), 90, COLOR_THEME_SECONDARY1) - + lcd.drawArc(CTR_X, CTR_Y, R2, 90 - ailDeg * math.min(1, 1 + dif), 90 + brkDeg, colors.primary3) drawRadian(90 - ailDeg * math.min(1, 1 + dif)) drawRadian(90) @@ -132,7 +132,7 @@ do lcd.drawText(CTR_X + R1, CTR_Y, "brake ", RIGHT + SMLSIZE + colors.primary1) lcd.drawText(CTR_X + R2, CTR_Y - SML_H, " max.", SMLSIZE + colors.primary1) lcd.drawText(CTR_X + R2, CTR_Y, " reflex", SMLSIZE + colors.primary1) - + local txt = "Use the slider to adjust the flaperons to the position of maximum reflex.\n\n" .. "Notice that camber can only move the flaperons down from this position." lcd.drawTextLines(MARGIN, TOP, CTR_X - 2 * MARGIN, LCD_H - TOP - MARGIN, txt, colors.primary1) @@ -178,6 +178,6 @@ function widget.refresh(event, touchState) setStickySwitch(LS_CTR, true) slider.value = model.getGlobalVariable(GV_BRK, 0) end - + gui.run(event, touchState) end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/brkcrv.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/brkcrv.lua index 8b0b2d6..9c9b74d 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/2/brkcrv.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/brkcrv.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = 0 local gui = nil local colors = libGUI.colors @@ -203,7 +203,7 @@ end -- Setup GUI function widget.background() if (gui ~= nil) then stepOff() - gui = nil + gui = nil end end -- background() diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/f3J.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/f3J.lua index 0872dad..92349f1 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/2/f3J.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/f3J.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = DBLSIZE local colors = libGUI.colors diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/f3k.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/f3k.lua index 7592147..b96ca2a 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/2/f3k.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/f3k.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = DBLSIZE local colors = libGUI.colors local activeGUI @@ -40,7 +40,7 @@ local RGT = LCD_W - 18 local TOP = 50 local BOTTOM = LCD_H - 30 local LINE = 60 -local LINE2 = 28 +local LINE2 = 28 local HEIGHT = 42 local HEIGHT2 = 18 local BUTTON_W = 86 @@ -82,7 +82,7 @@ local state -- Current program state local scores = { } -- List of saved scores local taskWindow = 0 -- Task window duration (zero counts up) local launches = -1 -- Number of launches allowed, -1 for unlimited -local taskScores = 0 -- Number of scores in task +local taskScores = 0 -- Number of scores in task local finalScores = false -- Task scores are final local targetType = 0 -- 1. Huge ladder, 2. Poker, 3. "1234", 4. Big ladder, Else: constant time local scoreType -- 1. Best, 2. Last, 3. Make time @@ -111,7 +111,7 @@ local SCORE_FILE = "/LOGS/JF F3K Scores.csv" -- Handle transitions between program states local function GotoState(newState) state = newState - + -- Stop blinking screenTask.timer0.blink = false @@ -126,13 +126,13 @@ local function GotoState(newState) setStickySwitch(LS_FLT_TMR, false) screenTask.labelTimer0.title = "Target:" screenTask.locked = true - + elseif state == STATE_FLYING then setStickySwitch(LS_WIN_TMR, true) setStickySwitch(LS_FLT_TMR, true) screenTask.labelTimer0.title = "Flight:" screenTask.locked = true - + if model.getTimer(0).start > 0 then -- Report the target time playDuration(model.getTimer(0).start, 0) @@ -140,35 +140,35 @@ local function GotoState(newState) -- ... or beep playTone(1760, 100, PLAY_NOW) end - + elseif state == STATE_COMMITTED then -- Call launch height if getLogicalSwitchValue(LS_ALT) then playNumber(getValue("Alt+"), UNIT_METERS) end - - if launches > 0 then + + if launches > 0 then launches = launches - 1 end - + lastChange = 0 - + elseif state == STATE_FINISHED then playTone(880, 1000, 0) end - + -- Configure "button3" screenTask.button3.disabled = false if state <= STATE_PAUSE then - screenTask.button3.title = "Start" + screenTask.button3.title = "Start" elseif state == STATE_WINDOW then screenTask.button3.title = "Pause" elseif state >= STATE_COMMITTED then screenTask.button3.title = "Zero" else - screenTask.button3.disabled = true + screenTask.button3.disabled = true end - + -- Configure info text label if state == STATE_PAUSE then screenTask.labelInfo.title = string.format("Total: %i sec.", totalScore) @@ -188,18 +188,18 @@ end -- GotoState() -- Function for setting up a task local function SetupTask(taskName, taskData) screenTask.title = taskName - + taskWindow = taskData[1] launches = taskData[2] taskScores = taskData[3] finalScores = taskData[4] targetType = taskData[5] scoreType = taskData[6] - screenTask.buttonQR.value = taskData[7] + screenTask.buttonQR.value = taskData[7] scores = { } totalScore = 0 pokerCalled = false - + -- Setup scores for i = 1, N_LINES do if i > taskScores then @@ -210,7 +210,7 @@ local function SetupTask(taskName, taskData) screenTask.scores[i].hidden = false end end - + -- A few extra counts in 1234 if targetType == 3 then counts = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30, 45, 65, 70, 75, 125, 130, 135, 185, 190, 195} @@ -236,7 +236,7 @@ local function RecordBest(scores, newScore) if newScore > scores[i] then j = i end i = i + 1 end - + if j == 0 then j = i end -- New score is smallest; end of the list end @@ -298,7 +298,7 @@ local function Score() end - totalScore = 0 + totalScore = 0 for i = 1, #scores do totalScore = totalScore + math.min(MaxScore(i), scores[i]) end @@ -307,7 +307,7 @@ end -- Score() -- Reset altimeter local function ResetAlt() for i = 0, 31 do - if model.getSensor(i).name == "Alt" then + if model.getSensor(i).name == "Alt" then model.resetSensor(i) break end @@ -370,11 +370,11 @@ end -- Best1234Target(..) -- Get called time from user in Poker local function PokerCall() local dial - + -- Find dials for setting target time in Poker and height ceilings etc. for input = 0, 31 do local tbl = model.getInput(input, 0) - + if tbl and tbl.name == "Dial" then dial = tbl.source end @@ -393,24 +393,24 @@ local function PokerCall() t2 = tblStep[i + 1][1] end local dt = tblStep[i][2] - + local result = t1 + dt * math.floor(x * (t2 - t1) /dt) - + if scoreType == 3 then result = math.min(winTimer - 1, result) end - + if math.abs(input - lastInput) >= 20 then lastInput = input lastChange = getTime() end - + if state == STATE_COMMITTED and lastChange > 0 and getTime() - lastChange > 100 then playTone(3000, 100, PLAY_NOW) playDuration(result) lastChange = 0 end - + return result end -- PokerCall() @@ -435,11 +435,11 @@ local function TargetTime() return MaxScore(#scores + 1) end end -- TargetTime() - + -- Initialize variables before flight local function InitializeFlight() local targetTime = TargetTime() - + -- Get ready to count down countIndex = #counts while countIndex > 1 and counts[countIndex] >= targetTime do @@ -468,7 +468,7 @@ function widget.background() ResetAlt() end - + -- Call altitude every 10 sec. if getLogicalSwitchValue(LS_ALT10) and now > nextCall then playNumber(getValue("Alt"), UNIT_METERS) @@ -478,11 +478,11 @@ function widget.background() if state <= STATE_READY and state ~= STATE_FINISHED then InitializeFlight() end - + flightTimer = model.getTimer(0).value flightTime = math.abs(model.getTimer(0).start - flightTimer) winTimer = model.getTimer(1).value - + if state < STATE_WINDOW then if state == STATE_IDLE then -- Set window timer @@ -515,7 +515,7 @@ function widget.background() -- Play tone to warn that timer is NOT running playTone(1760, 200, 0, PLAY_NOW) end - + elseif state == STATE_READY then if launchReleased then GotoState(STATE_FLYING) @@ -533,12 +533,12 @@ function widget.background() elseif flightTimer > 0 and math.ceil(flightTimer / 60) < math.ceil(prevFt / 60) then playDuration(flightTimer, 0) end - + -- Blink when flight ttimer is negative if flightTimer < 0 then screenTask.timer0.blink = true end - + if state == STATE_FLYING then -- Within 10 sec. "grace period", cancel the flight if launchPulled then @@ -549,7 +549,7 @@ function widget.background() if flightTime >= 10 then GotoState(STATE_COMMITTED) end - + elseif launchPulled then -- Report the time after flight is done if model.getTimer(0).start == 0 then @@ -557,7 +557,7 @@ function widget.background() end Score() - + -- Change state if (finalScores and #scores == taskScores) or launches == 0 or (taskWindow > 0 and winTimer <= 0) then GotoState(STATE_FINISHED) @@ -568,7 +568,7 @@ function widget.background() end end end - + prevWt = winTimer prevFt = flightTimer end @@ -622,12 +622,12 @@ function libGUI.widgetRefresh() local COL2 = COL1 + 30 local COL3 = COL1 + 125 local RGT = COL1 + 400 - + -- Draw scores x = 5 local y = 0 local dy = widget.zone.h / N_LINES - + for i = 1, taskScores do lcd.drawText(COL1, y, string.format("%i.", i), colors.primary1 + DBLSIZE) if i > #scores then @@ -641,14 +641,14 @@ function libGUI.widgetRefresh() -- Draw timers local blink = 0 local y = 4 - + local tmr = model.getTimer(0).value - if tmr < 0 and state == STATE_COMMITTED then + if tmr < 0 and state == STATE_COMMITTED then blink = BLINK end lcd.drawText(COL3, y + 10, screenTask.labelTimer0.title, colors.primary1 + DBLSIZE) - lcd.drawTimer(RGT, y, tmr, colors.primary1 + blink + XXLSIZE + RIGHT) + lcd.drawTimer(RGT, y, tmr, colors.primary1 + blink + XXLSIZE + RIGHT) y = y + 2 * dy tmr = model.getTimer(1).value lcd.drawText(COL3, y + 10, "Task:", colors.primary1 + DBLSIZE) @@ -660,13 +660,13 @@ end -- widgetRefresh() local function SetupScreen(gui, title, pop) gui.title = title local x1 - + if pop then x1 = LCD_W - 80 else x1 = LCD_W - 50 end - + function gui.fullScreenRefresh() local color lcd.clear(COLOR_THEME_SECONDARY3) @@ -678,17 +678,17 @@ local function SetupScreen(gui, title, pop) -- Date local now = getDateTime() local str = string.format("%02i:%02i", now.hour, now.min) - lcd.drawText(x1, 6, str, RIGHT + MIDSIZE + colors.primary2) + lcd.drawText(x1, 6, str, RIGHT + MIDSIZE + colors.primary2) if soarGlobals.battery == 0 then color = COLOR_THEME_DISABLED else color = colors.primary2 end - + str = string.format("%1.1fV", soarGlobals.battery) lcd.drawText(x1 - 65, 6, str, RIGHT + MIDSIZE + color) - + -- Draw trims local p = { { LCD_W - 191, LCD_H - 14, 177, 8 }, @@ -696,7 +696,7 @@ local function SetupScreen(gui, title, pop) { LCD_W - 14, 68, 8, 177 }, { 7, 68, 8, 177 }, } - + for i = 1, 4 do local q = p[i] local value = getValue(trimSources[i]) / 10.24 @@ -708,21 +708,21 @@ local function SetupScreen(gui, title, pop) x = q[1] + q[3] / 2 y = q[2] + q[4] * (100 - value) / 200 end - + lcd.drawFilledRectangle(q[1], q[2], q[3], q[4], COLOR_THEME_SECONDARY1) lcd.drawFilledRectangle(x - 9, y - 6, 18, 15, colors.primary1) lcd.drawFilledRectangle(x - 10, y - 7, 18, 15, colors.focus) lcd.drawNumber(x, y, value, SMLSIZE + VCENTER + CENTER + colors.primary2) end - + -- Flight mode - lcd.drawText(LCD_W / 2, LCD_H - LINE2, select(2, getFlightMode()), MIDSIZE + CENTER + COLOR_THEME_SECONDARY1) + lcd.drawText(LCD_W / 2, LCD_H - LINE2, select(2, getFlightMode()), MIDSIZE + CENTER + COLOR_THEME_SECONDARY1) end -- fullScreenRefresh() - + -- Return button if pop then gui.buttonRet = gui.custom({ }, LCD_W - 74, 6, 28, 28) - + function gui.buttonRet.draw(focused) local color @@ -733,14 +733,14 @@ local function SetupScreen(gui, title, pop) color = COLOR_THEME_DISABLED gui.buttonRet.disabled = true end - + lcd.drawRectangle(LCD_W - 74, 6, 28, 28, color) lcd.drawFilledRectangle(LCD_W - 61, 12, 3, 18, color) for i = 0, 3 do lcd.drawLine(LCD_W - 60 , 10 + i, LCD_W - 50 - i, 20, SOLID, color) lcd.drawLine(LCD_W - 60 , 10 + i, LCD_W - 70 + i, 20, SOLID, color) end - + if focused then gui.buttonRet.drawFocus() end @@ -752,7 +752,7 @@ local function SetupScreen(gui, title, pop) end end end - + -- Minimize button local buttonMin = gui.custom({ }, LCD_W - 34, 6, 28, 28) @@ -764,7 +764,7 @@ local function SetupScreen(gui, title, pop) buttonMin.drawFocus() end end - + function buttonMin.onEvent(event) if event == EVT_VIRTUAL_ENTER then lcd.exitFullScreen() @@ -780,7 +780,7 @@ local function SetupScreen(gui, title, pop) end end gui.setEventHandler(EVT_VIRTUAL_EXIT, HandleEXIT) - + return gui end -- SetupScreen @@ -791,7 +791,7 @@ do local ROW = 65 x = 40 y = 60 - + SetupScreen(menuMain, "SoarETX F3K") -- Generate callbacks with closure for calling submenus @@ -806,7 +806,7 @@ do menuMain.button(x, y, WIDTH, HEIGHT, "Practice", MakePush(menuPractice)) y = y + ROW menuMain.button(x, y, WIDTH, HEIGHT, "Scores", MakePush(menuScores)) - + activeGUI = menuMain end @@ -831,7 +831,7 @@ do -- Setup F3K tasks menu "L. One flight only", "M. Huge Ladder" } - + -- {win, launches, scores, final, tgtType, scoType, QR } local taskData = { { 420, -1, 1, false, 300, 2, false }, -- A. Last flight @@ -862,7 +862,7 @@ end do -- Setup practice tasks menu SetupScreen(menuPractice, "Practice Tasks", true) - + local tasks = { "Just Fly!", "Quick Relaunch!", @@ -875,7 +875,7 @@ do -- Setup practice tasks menu { 0, -1, 5, false, 2, 2, true }, -- QR { 600, 2, 2, true, 5, 2, false } -- Deuces } - + -- Call back function running when a menu item is selected local function callBack(menu) SetupTask(tasks[menu.selected], taskData[menu.selected]) @@ -888,13 +888,13 @@ end do -- Setup score keeper screen for F3K and Practice tasks SetupScreen(screenTask, "", true) - + -- Restore default task and dismiss task screen - function screenTask.dismiss() + function screenTask.dismiss() SetupTask("Just Fly!", { 0, -1, 5, false, 0, 2, false }) PopGUI() end - + -- Return button shows prompt to save scores instead of popping right away function screenTask.buttonRet.onEvent(event) if event == EVT_VIRTUAL_ENTER then @@ -905,17 +905,17 @@ do -- Setup score keeper screen for F3K and Practice tasks end end end - + -- Add score times local y = TOP local dy = select(2, lcd.sizeText("", libGUI.flags)) - + screenTask.scoreLabels = { } screenTask.scores = { } for i = 1, N_LINES do screenTask.scoreLabels[i] = screenTask.label(LEFT, y, 20, HEIGHT, string.format("%i.", i)) - + local s = screenTask.timer(LEFT + 40, y, 60, HEIGHT, 0, nil) s.disabled = true s.value = "- - -" @@ -924,35 +924,35 @@ do -- Setup score keeper screen for F3K and Practice tasks -- Modify timer's draw function to insert score value local draw = s.draw function s.draw(idx) - if i > #scores then + if i > #scores then screenTask.scores[i].value = "- - -" else screenTask.scores[i].value = scores[i] end - + draw(idx) end y = y + dy end - + -- Add center buttons local y = TOP screenTask.buttonQR = screenTask.toggleButton(COL2, y, BUTTON_W, HEIGHT, "QR", false, nil) y = y + LINE screenTask.buttonEoW = screenTask.toggleButton(COL2, y, BUTTON_W, HEIGHT, "EoW", true, nil) - + local function callBack(button) if state <= STATE_PAUSE then GotoState(STATE_WINDOW) - + elseif state == STATE_WINDOW then GotoState(STATE_PAUSE) - + elseif state >= STATE_COMMITTED then -- Record a zero score! flightTime = 0 Score() - + -- Change state if winTimer <= 0 or (finalScores and #scores == taskScores) or launches == 0 then GotoState(STATE_FINISHED) @@ -962,26 +962,26 @@ do -- Setup score keeper screen for F3K and Practice tasks end end end - + y = y + LINE screenTask.button3 = screenTask.button(COL2, y, BUTTON_W, HEIGHT, "Start", callBack) - + -- Info text label screenTask.labelInfo = screenTask.label(RGT - 250, BOT_ROW, 250, HEIGHT, "", libGUI.flags + RIGHT) - + -- Add timers y = TOP screenTask.labelTimer0 = screenTask.label(RGT - 160, y, 50, HEIGHT2, "Target:", MIDSIZE) y = y + LINE2 screenTask.timer0 = screenTask.timer(RGT - 160, y, 160, HEIGHT, 0, nil, XXLSIZE + RIGHT) screenTask.timer0.disabled = true - + y = y + LINE screenTask.label(RGT - 160, y, 50, HEIGHT2, "Task:", MIDSIZE) y = y + LINE2 local tmr = screenTask.timer(RGT - 160, y, 160, HEIGHT, 1, nil, XXLSIZE + RIGHT) tmr.disabled = true - + -- Short press EXIT handler must prompt to save scores local function HandleEXIT(event, touchState) if CanPopGUI() then @@ -1001,7 +1001,7 @@ do -- Prompt asking to save scores and exit task window local RGT = x0 + PROMPT_W - PROMPT_M local TOP = y0 + PROMPT_M local BOTTOM = y0 + PROMPT_H - PROMPT_M - + function promptSaveScores.fullScreenRefresh() lcd.drawFilledRectangle(x0, y0, PROMPT_W, PROMPT_H, colors.primary2) lcd.drawRectangle(x0, y0, PROMPT_W, PROMPT_H, colors.primary1, 3) @@ -1015,21 +1015,21 @@ do -- Prompt asking to save scores and exit task window if scoreFile then io.write(scoreFile, string.format("%s,%s", model.getInfo().name, screenTask.title)) - local now = getDateTime() + local now = getDateTime() io.write(scoreFile, string.format(",%04i-%02i-%02i", now.year, now.mon, now.day)) - io.write(scoreFile, string.format(",%02i:%02i", now.hour, now.min)) + io.write(scoreFile, string.format(",%02i:%02i", now.hour, now.min)) io.write(scoreFile, string.format(",s,%i", taskScores)) io.write(scoreFile, string.format(",%i", totalScore)) - + for i = 1, #scores do io.write(scoreFile, string.format(",%i", scores[i])) end - + io.write(scoreFile, "\n") io.close(scoreFile) end end - + -- Dismiss prompt and return to menu screenTask.dismissPrompt() screenTask.dismiss() @@ -1047,7 +1047,7 @@ do -- Setup score browser screen local scoreFile -- File handle local pos -- Read position in file local firstRecordTouch -- First record at the start of touch slide - + -- Read a line of a log file local function ReadLine(scoreFile, pos) if scoreFile and pos then @@ -1061,7 +1061,7 @@ do -- Setup score browser screen return pos, str end end - + -- No "\n" was found; return nothing return 0, "" end -- ReadLine() @@ -1074,7 +1074,7 @@ do -- Setup score browser screen for field in string.gmatch(str, "[^,]+") do i = i + 1 - + if i == 1 then record.planeName = field elseif i == 2 then @@ -1093,33 +1093,33 @@ do -- Setup score browser screen record.scores[#record.scores + 1] = tonumber(field) end end - + if record.totalScore then records[#records + 1] = record end end -- ReadLineData() - + local function DrawRecord(i, r) local top = 40 + i * RECORD_H local left = 200 local w = (LCD_W - left - 10) / 3 local record = records[r] - + if not record then return end - + if r % 2 == 0 then lcd.drawFilledRectangle(0, top, LCD_W, RECORD_H, COLOR_THEME_SECONDARY2) end - + lcd.drawText(10, top + 6, record.taskName, BOLD) lcd.drawText(10, top + 24, record.dateStr .. " " .. record.timeStr, SMLSIZE) lcd.drawText(10, top + 36, record.planeName, SMLSIZE) - + local x = left local y = top + 6 - + for j = 1, math.min(5, record.taskScores) do lcd.drawText(x, y, j .. ".") @@ -1130,7 +1130,7 @@ do -- Setup score browser screen else lcd.drawText(x + 18, y, record.scores[j] .. record.unitStr) end - + if j == 3 then x = left y = top + 30 @@ -1138,7 +1138,7 @@ do -- Setup score browser screen x = x + w end end - + lcd.drawText(left + 2 * w, top + 30, "Total: " .. record.totalScore .. record.unitStr) end -- DrawRecord @@ -1152,7 +1152,7 @@ do -- Setup score browser screen end lcd.clear(COLOR_THEME_SECONDARY3) - + -- Top bar lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) lcd.drawText(10, 2, "Score Card", bit32.bor(DBLSIZE, colors.primary2)) @@ -1160,25 +1160,25 @@ do -- Setup score browser screen -- Date local now = getDateTime() local str = string.format("%02i:%02i", now.hour, now.min) - lcd.drawText(LCD_W - 80, 6, str, RIGHT + MIDSIZE + colors.primary2) + lcd.drawText(LCD_W - 80, 6, str, RIGHT + MIDSIZE + colors.primary2) if soarGlobals.battery == 0 then color = COLOR_THEME_DISABLED else color = colors.primary2 end - + str = string.format("%1.1fV", soarGlobals.battery) lcd.drawText(LCD_W - 140, 6, str, RIGHT + MIDSIZE + color) - + -- Return button lcd.drawFilledRectangle(LCD_W - 74, 6, 28, 28, COLOR_THEME_SECONDARY1) lcd.drawRectangle(LCD_W - 74, 6, 28, 28, colors.primary2) - + for i = -1, 1 do lcd.drawLine(LCD_W - 60 + i, 12, LCD_W - 60 + i, 30, SOLID, colors.primary2) end - + for i = 0, 3 do lcd.drawLine(LCD_W - 60 , 10 + i, LCD_W - 50 - i, 20, SOLID, colors.primary2) lcd.drawLine(LCD_W - 60 , 10 + i, LCD_W - 70 + i, 20, SOLID, colors.primary2) @@ -1188,17 +1188,17 @@ do -- Setup score browser screen lcd.drawFilledRectangle(LCD_W - 34, 6, 28, 28, COLOR_THEME_SECONDARY1) lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) lcd.drawFilledRectangle(LCD_W - 30, 19, 20, 3, colors.primary2) - + if event ~= EVT_TOUCH_SLIDE then firstRecordTouch = nil end - + if event == EVT_VIRTUAL_EXIT then firstRecord = nil return PopGUI() elseif event == EVT_TOUCH_TAP then local x, y = touchState.x, touchState.y - + if 6 <= y and y <= 34 then if LCD_W - 74 <= x and x <= LCD_W - 40 then firstRecord = nil @@ -1226,9 +1226,9 @@ do -- Setup score browser screen local r = i + firstRecord DrawRecord(i, r) end - + else -- Read score records - lcd.drawText(LCD_W / 2, LCD_H / 2, "Reading scores ...", VCENTER + CENTER + DBLSIZE + colors.primary1) + lcd.drawText(LCD_W / 2, LCD_H / 2, "Reading scores ...", VCENTER + CENTER + DBLSIZE + colors.primary1) if not scoreFile then scoreFile = io.open(SCORE_FILE, "r") @@ -1237,7 +1237,7 @@ do -- Setup score browser screen records = { } end end - + if scoreFile then for i = 1, 10 do local str @@ -1247,11 +1247,11 @@ do -- Setup score browser screen io.close(scoreFile) scoreFile = nil firstRecord = math.max(1, #records - 3) - + if #records == 0 then firstRecord = nil end - + break end end diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/f5J.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/f5J.lua index d2e5f60..246e1ca 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/2/f5J.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/f5J.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = DBLSIZE local colors = libGUI.colors @@ -291,7 +291,7 @@ function widget.background() if motorOn then GotoState(STATE_MOTOR) -- Reset MotorTime Call and Alt Window Time - prevMt = flightTimer.value + prevMt = flightTimer.value offTime = 0 end elseif state == STATE_MOTOR then diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/graph.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/graph.lua index 97bdc70..95225a0 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/2/graph.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/graph.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = 0 local colors = libGUI.colors local title = "Graph" diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/mixes.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/mixes.lua index 46498d4..c774b9c 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/2/mixes.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/mixes.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = 0 local gui = libGUI.newGUI() local colors = libGUI.colors @@ -84,40 +84,40 @@ local mixes = mixes_F3K do -- Extract Model Type from parametes - modelType = widget.options.Type + modelType = widget.options.Type if modelType == "F3K" or modelType == "F3K_TRAD" then mixes = mixes_F3K elseif modelType == "F3K_FH" then mixes = mixes_F3K_FH elseif modelType == "F3K_RE" then - mixes = mixes_F3K_RE + mixes = mixes_F3K_RE elseif modelType == "F3J" or modelType == "F5J" then - mixes = mixes_FxJ + mixes = mixes_FxJ else - mixes = mixes_FXY + mixes = mixes_FXY modelType = "F??" end function gui.fullScreenRefresh() lcd.clear(COLOR_THEME_SECONDARY3) - + -- Top bar lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) lcd.drawText(10, 2, title.." "..modelType, bit32.bor(DBLSIZE, colors.primary2)) - + -- Fligh mode local fmIdx, fmStr = getFlightMode() lcd.drawText(LCD_W - HEADER, HEADER / 2, "FM" .. fmIdx .. ":" .. fmStr, RIGHT + VCENTER + MIDSIZE + colors.primary2) - + -- Line stripes for i = 1, 3, 2 do lcd.drawFilledRectangle(0, HEADER + LINE * i, LCD_W, LINE, COLOR_THEME_SECONDARY2) end - + local bottom = HEADER + 4 * LINE lcd.drawLine(LCD_W2, HEADER, LCD_W2, bottom, SOLID, colors.primary1) - + -- Help text local txt = "Some variables can be adjusted individually for each flight mode.\n" .. "Therefore, select the flight mode for which you want to adjust.\n" .. @@ -145,7 +145,7 @@ do -- Grid for items local x, y = MARGIN, HEADER + 2 - + local function move() if x == MARGIN then x = x + LCD_W2 @@ -154,11 +154,11 @@ do y = y + LINE end end - + -- Add label and number element for a GV local function addGV(label, gv, min, max) gui.label(x, y, W1, HEIGHT, label) - + local function changeGV(delta, number) local value = number.value + delta value = math.max(value, min) @@ -166,16 +166,16 @@ do model.setGlobalVariable(gv, fm, value) return value end - + local number = gui.number(x + W1, y, W2, HEIGHT, 0, changeGV, RIGHT + libGUI.flags) - + function number.update() number.value = model.getGlobalVariable(gv, fm) end - + move() end - + -- ADD GVs for i, mix in ipairs(mixes) do addGV(mix[1], mix[2], mix[3], mix[4]) @@ -191,7 +191,7 @@ do soarGlobals.setParameter(soarGlobals.batteryParameter, value - 100) return value end - + local batP = soarGlobals.getParameter(soarGlobals.batteryParameter) gui.number(x + W1, y, W2, HEIGHT, batP + 100, changeBattery, RIGHT + PREC1 + libGUI.flags) end -- Setup GUI @@ -206,8 +206,8 @@ function widget.refresh(event, touchState) lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) return end - + fm = getFlightMode() - + gui.run(event, touchState) end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/outputs.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/outputs.lua index a073891..b9d7674 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/2/outputs.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/outputs.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = MIDSIZE local gui local colors = libGUI.colors @@ -75,12 +75,12 @@ do local PROMPT_H = 172 warningPrompt.x = (LCD_W - PROMPT_W) / 2 warningPrompt.y = (LCD_H - PROMPT_H) / 2 - + function warningPrompt.fullScreenRefresh() local txt = "Please disable the motor!\n\n" .. "Sudden spikes may occur when channels are moved.\n\n" .. "Press ENTER to proceed." - + warningPrompt.drawFilledRectangle(0, 0, PROMPT_W, HEADER, COLOR_THEME_SECONDARY1) warningPrompt.drawFilledRectangle(0, HEADER, PROMPT_W, PROMPT_H - HEADER, libGUI.colors.primary2) warningPrompt.drawRectangle(0, 0, PROMPT_W, PROMPT_H, libGUI.colors.primary1, 2) @@ -125,7 +125,7 @@ do } editPrompt.x = (LCD_W - PROMPT_W) / 2 editPrompt.y = (LCD_H - PROMPT_H) / 2 - + function editPrompt.fullScreenRefresh() if not editPrompt.editing then editPoints = 0 @@ -138,7 +138,7 @@ do editPrompt.drawFilledRectangle(0, HEADER, PROMPT_W, PROMPT_H - HEADER, libGUI.colors.primary2) editPrompt.drawRectangle(0, 0, PROMPT_W, PROMPT_H, libGUI.colors.primary1, 2) editPrompt.drawText(MARGIN, HEADER / 2, "Select what to edit:", DBLSIZE + VCENTER + libGUI.colors.primary2) - + local y = HEADER + MARGIN + h / 2 for i = 1, 5 do @@ -162,7 +162,7 @@ do editPoints = menu.selected gui.dismissPrompt() end -- onMenu(...) - + editPrompt.menu(MARGIN, HEADER + MARGIN, MENU_W, MENU_H, menuItems, onMenu) end -- Prompt for selecting what to edit @@ -171,13 +171,13 @@ local function MoveOutput(direction, channel) local m = { } -- Channel indices m[1] = channel.iChannel -- Channel to move m[2] = m[1] + direction -- Neighbouring channel to swap - + -- Are we at then end? if m[2] < 1 or m[2] > N then playTone(3000, 100, 0, PLAY_NOW) return end - + local outputs = { } -- List of output tables local mixes = { } -- List of lists of mixer tables @@ -191,7 +191,7 @@ local function MoveOutput(direction, channel) mixes[i][j] = model.getMix(m[i] - 1, j - 1) end end - + -- Write back swapped data for i = 1, 2 do model.setOutput(m[i] - 1, outputs[3 - i]) @@ -223,7 +223,7 @@ local function MoveOutput(direction, channel) mixes[j].source = m[1] + CHAN_BASE end end - + -- Do we have to write back data? if dirty then -- Delete existing mixer lines @@ -262,7 +262,7 @@ local function init() -- Top bar lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) lcd.drawText(MARGIN, HEADER / 2 - 2, "Configure Outputs", DBLSIZE + VCENTER + colors.primary2) - + -- Row background for i = 0, 6 do local y = HEADER + i * ROW @@ -272,7 +272,7 @@ local function init() lcd.drawFilledRectangle(0, y, LCD_W, ROW, COLOR_THEME_SECONDARY3) end end - + -- Adjust scroll for channels if focusNamed > 0 then if focusNamed < firstLine then @@ -282,7 +282,7 @@ local function init() end end focusNamed = 0 - + -- Draw vertical reference lines for i = -6, 6 do local x = CTR - i * MAXOUT / (SCALE * 6) + 2 @@ -313,10 +313,10 @@ local function init() local HEIGHT = ROW - 8 local iNamed = 0 channels = { } - + for iChannel = 1, N do local output = model.getOutput(iChannel - 1) - + if output and output.name ~= "" then local channel = gui.gui(2, LCD_H, LCD_W - 4, ROW - 4) local d0 @@ -356,8 +356,8 @@ local function init() end -- onEvent(...) -- Custom element for changing output channel (and moving all mixer lines etc.) - local nbrChannel = channel.custom({ }, 2, 2, 30, HEIGHT) - + local nbrChannel = channel.custom({ }, 2, 2, 30, HEIGHT) + function nbrChannel.draw(focused) local fg = libGUI.colors.primary1 if focused then @@ -391,13 +391,13 @@ local function init() channel.editing = true end end -- onEvent(...) - + -- Label for channel name local lblName = channel.label(32, 2, 140, HEIGHT, ". " .. channel.output.name) - + -- Custom element to invert output direction local revert = channel.custom({ }, 172, 2, 30, HEIGHT) - + function revert.draw(focused) local y = HEIGHT / 2 + 3 if channel.output.revert == 1 then @@ -413,7 +413,7 @@ local function init() channel.drawLine(x, y, x - 8, y + 8, SOLID, colors.primary1) end end - + function revert.onEvent(event, touchState) if event == EVT_VIRTUAL_ENTER then channel.output.revert = 1 - channel.output.revert @@ -435,14 +435,14 @@ local function init() local y = HEIGHT / 2 + 2 local yLbl = y - 12 - select(2, lcd.sizeText("", flags)) local iScroll = 0 - + function interval.draw(focused) local output = channel.output local p = { 0, 0, 0 } local colorBar = libGUI.colors.primary3 local colorDot = libGUI.colors.primary2 local colorDotBorder = libGUI.colors.primary3 - + x = { CTR + output.min / SCALE, CTR + output.offset / SCALE, @@ -457,7 +457,7 @@ local function init() channel.drawNumber(x[3], yLbl, 0.1 * output.max, flags) colorBar = libGUI.colors.primary1 colorDot = libGUI.colors.edit - p = activePoints(editPoints) + p = activePoints(editPoints) else interval.drawFocus() end @@ -477,21 +477,21 @@ local function init() -- Draw position indicators local outX = getValue(CHAN_BASE + channel.iChannel) if outX >= 0 then - outX = output.offset + math.min(outX, 1024) * (output.max - output.offset) / 1024 + outX = output.offset + math.min(outX, 1024) * (output.max - output.offset) / 1024 else - outX = output.offset + math.max(outX, -1024) * (output.offset - output.min) / 1024 + outX = output.offset + math.max(outX, -1024) * (output.offset - output.min) / 1024 end outX = CTR + outX / SCALE channel.drawFilledTriangle(outX, y - 3, outX - 3, y - 9, outX + 3, y - 9, colorBar) channel.drawLine(outX, y - 2, outX, y + 2, SOLID, colorBar) channel.drawFilledTriangle(outX, y + 3, outX - 3, y + 9, outX + 3, y + 9, colorBar) end -- draw(...) - + local RR = 14 ^ 2 - + local function ptCovers(p, q) local ap = activePoints(editPoints) - + for i = 1, 3 do if ap[i] ~= 0 and (x[i] - p) ^ 2 + (y - q) ^ 2 <= RR then return i @@ -499,46 +499,46 @@ local function init() end return 0 end -- ptCovers(...) - + local function adjustPoints(d) local output = channel.output local p = activePoints(editPoints) local min = output.min local ctr = output.offset local max = output.max - + -- Check limits if p[1] == -1 then d = math.min(d, math.max(0, MAXOUT + min)) elseif p[1] == 1 then d = math.max(d, math.min(0, -(MAXOUT + min))) end - + if p[2] - p[1] == 1 then d = math.max(d, math.min(0, MINDIF + min - ctr)) elseif p[2] - p[1] == -1 then d = math.min(d, math.max(0, ctr - min - MINDIF)) end - + if p[3] - p[2] == 1 then d = math.max(d, math.min(0, MINDIF + ctr - max)) elseif p[3] - p[2] == -1 then d = math.min(d, math.max(0, max - ctr - MINDIF)) end - + if p[3] == 1 then d = math.min(d, math.max(0, MAXOUT - max)) end - + -- Update output values output.min = min + p[1] * d output.offset = ctr + p[2] * d output.max = max + p[3] * d - + -- Write back data model.setOutput(channel.iChannel - 1, output) end - + function interval.onEvent(event, touchState) if event == EVT_VIRTUAL_ENTER and not channel.editing then channel.editing = true @@ -586,7 +586,7 @@ function widget.refresh(event, touchState) init() return end - + gui.run(event, touchState) end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/switch.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/switch.lua index 4bcc052..cb6e33e 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/2/switch.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/switch.lua @@ -21,7 +21,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = 0 local gui local colors = libGUI.colors @@ -37,53 +37,53 @@ local WIDTH = 60 local COL2 = LCD_W - MARGIN - WIDTH -- List of 1. Text label 2. logical switch -local items_F3K = { -- For R3K - { "Allow vario and voice reporting of altitude", 0 }, +local items_F3K = { -- For R3K + { "Allow vario and voice reporting of altitude", 0 }, { "Variometer sound", 1 }, - { "Speed flight mode", 2 }, - { "Float flight mode", 3 }, - { "Report remaining window time every 10 sec.", 4 }, - { "Report current altitude every 10 sec.", 5 }, - { "Launch mode and flight timer control", 6 }, + { "Speed flight mode", 2 }, + { "Float flight mode", 3 }, + { "Report remaining window time every 10 sec.", 4 }, + { "Report current altitude every 10 sec.", 5 }, + { "Launch mode and flight timer control", 6 }, { "Data logging (when flight timer is running)", 7 } } -local items_F3K_RE = { -- For R3K_RE - { "Allow vario and voice reporting of altitude", 0 }, +local items_F3K_RE = { -- For R3K_RE + { "Allow vario and voice reporting of altitude", 0 }, { "Variometer sound", 1 }, - { "Speed flight mode", 2 }, - { "Report remaining window time every 10 sec.", 4 }, - { "Report current altitude every 10 sec.", 5 }, - { "Launch mode and flight timer control", 6 }, + { "Speed flight mode", 2 }, + { "Report remaining window time every 10 sec.", 4 }, + { "Report current altitude every 10 sec.", 5 }, + { "Launch mode and flight timer control", 6 }, { "Data logging (when flight timer is running)", 7 } } -local items_F5K = { - { "Allow vario and voice reporting of altitude", 0 }, +local items_F5K = { + { "Allow vario and voice reporting of altitude", 0 }, { "Variometer sound", 1 }, - { "Speed flight mode", 2 }, - { "Float flight mode", 3 }, + { "Speed flight mode", 2 }, + { "Float flight mode", 3 }, { "Motor ARM ON/OFF", 4}, - { "Report remaining window time every 10 sec.", 5 }, - { "Report current altitude every 10 sec.", 6 }, - { "Launch mode and flight timer control", 7 }, + { "Report remaining window time every 10 sec.", 5 }, + { "Report current altitude every 10 sec.", 6 }, + { "Launch mode and flight timer control", 7 }, { "Data logging (when flight timer is running)", 8 } } local items_FxJ = { - { "Allow vario and voice reporting of altitude", 0 }, - { "Variometer sound", 1 }, - { "Speed flight mode", 2 }, - { "Float flight mode", 3 }, - { "Report remaining window time every 10 sec.", 6 }, - { "Report current altitude every 10 sec.", 7 }, - { "Launch mode (Motor Arm) and flight timer control", 4 }, - { "Start/Stop timer and Motor", 8 }, - { "Data logging (when flight timer is running)", 9 } + { "Allow vario and voice reporting of altitude", 0 }, + { "Variometer sound", 1 }, + { "Speed flight mode", 2 }, + { "Float flight mode", 3 }, + { "Report remaining window time every 10 sec.", 6 }, + { "Report current altitude every 10 sec.", 7 }, + { "Launch mode (Motor Arm) and flight timer control", 4 }, + { "Start/Stop timer and Motor", 8 }, + { "Data logging (when flight timer is running)", 9 } } local items_FXY = { - { "Allow vario and voice reporting of altitude", 0 } + { "Allow vario and voice reporting of altitude", 0 } } local items = items_FXY @@ -130,11 +130,11 @@ local function init() -- Build the list of drop downs local y = HEADER + 2 local w1 = COL2 - MARGIN - + -- Build lists of physical switch position indices and names local swIndices = { } local swNames = { } - + for swIdx, swName in switches() do if string.find(swName,"^!?S[A-H][+-]?") then i = #swIndices + 1 @@ -149,9 +149,9 @@ local function init() lsTbl.v1 = swIdx model.setLogicalSwitch(dropDown.ls, lsTbl) end - + -- Extract Model Type from parametes - modelType = widget.options.Type + modelType = widget.options.Type if modelType == "F3K" or modelType == "F3K_FH" or modelType == "F3K_TRAD" then items = items_F3K @@ -162,27 +162,27 @@ local function init() HEIGHT = 20 LINE = 25 elseif modelType == "F3J" or modelType == "F5J" then - items = items_FxJ + items = items_FxJ HEIGHT = 20 -- Make it smaller to fit extra line LINE = 25 else - items = items_FXY + items = items_FXY modelType = "F??" end for i, item in ipairs(items) do gui.label(MARGIN, y, w1, HEIGHT, item[1]) - + local swIdx = model.getLogicalSwitch(item[2]).v1 local selected = 0 - + for i, idx in ipairs(swIndices) do if swIdx == idx then selected = i break end end - + if selected == 0 then -- Oops, no switch matching current value in LS! gui.label(COL2, y, WIDTH, HEIGHT, "???", CENTER + BOLD) @@ -210,6 +210,6 @@ function widget.refresh(event, touchState) init() return end - + gui.run(event, touchState) end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/wing2.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/wing2.lua index 78a7282..05fae03 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/2/wing2.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/wing2.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = MIDSIZE local gui = nil local colors = libGUI.colors @@ -268,7 +268,7 @@ local function setup_gui() gui = libGUI.newGUI() -- Extract Model Type from parametes - modelType = widget.options.Type + modelType = widget.options.Type if modelType == "F3K" or modelType == "F3K_TRAD" then LS_STEP = 10 -- Logical Switch 10 diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/wing4.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/wing4.lua index b7b112a..910fbd8 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/2/wing4.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/wing4.lua @@ -20,7 +20,7 @@ --------------------------------------------------------------------------- local widget, soarGlobals = ... -local libGUI = loadGUI() +local libGUI = soarGlobals.libGUI libGUI.flags = MIDSIZE local gui = nil local colors = libGUI.colors @@ -43,7 +43,7 @@ local BUTTON_Y = (LCD_H + TOP + HEIGHT - BUTTON_H) / 2 -- Other constants local INP_STEP = getFieldInfo("input8").id -- Step input local LS_STEP = nil -- Set this LS to apply step input and adjust -local GV_ADJUST = nil +local GV_ADJUST = nil local N = 5 -- Number of curve points local MAX_Y = 1500 -- Max output value local MINDIF = 100 -- Minimum difference between lower, center and upper values @@ -287,16 +287,16 @@ local function setup_gui() gui = libGUI.newGUI() -- Extract Model Type from parametes - modelType = widget.options.Type + modelType = widget.options.Type if modelType == "F3K_FH" then LS_STEP = 10 -- L11 elseif modelType == "F3J" or modelType == "F5J" then - GV_ADJUST = 7 -- GV8:Adj + GV_ADJUST = 7 -- GV8:Adj else LS_STEP = nil modelType = "F??" end - + function gui.fullScreenRefresh() lcd.clear(COLOR_THEME_SECONDARY3) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/libgui.lua b/sdcard/c480x272/WIDGETS/SoarETX/libgui.lua new file mode 100644 index 0000000..d9c6dcd --- /dev/null +++ b/sdcard/c480x272/WIDGETS/SoarETX/libgui.lua @@ -0,0 +1,1125 @@ +--------------------------------------------------------------------------- +-- The dynamically loadable part of the shared Lua GUI library. -- +-- -- +-- Author: Jesper Frickmann -- +-- Version: 1.0.0 Date: 2021-12-20 -- +-- Version: 1.0.1 Date: 2022-05-05 -- +-- Version: 1.0.2 Date: 2022-11-20 -- +-- Version: 1.0.2 Date: 2023-07 -- +-- Version: 1.0.3 Date: 2023-12 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html -- +-- -- +-- This program is free software; you can redistribute it and/or modify -- +-- it under the terms of the GNU General Public License version 2 as -- +-- published by the Free Software Foundation. -- +-- -- +-- 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 General Public License for more details. -- +--------------------------------------------------------------------------- + +local app_ver = "1.0.3" + +local M = { } + +-- Radius of slider dot +M.SLIDER_DOT_RADIUS = 10 + +-- better font size names +M.FONT_SIZES = { + FONT_38 = XXLSIZE, -- 38px + FONT_16 = DBLSIZE, -- 16px + FONT_12 = MIDSIZE, -- 12px + FONT_8 = 0, -- Default 8px + FONT_6 = SMLSIZE, -- 6px +} + +-- Default flags and colors, can be changed by client +M.flags = 0 +M.colors = { + primary1 = COLOR_THEME_PRIMARY1, + primary2 = COLOR_THEME_PRIMARY2, -- button background / topbar text + primary3 = COLOR_THEME_PRIMARY3, -- button text + secondary1 = COLOR_THEME_SECONDARY1, -- topbar background + secondary2 = COLOR_THEME_SECONDARY2, -- button border + secondary3 = COLOR_THEME_SECONDARY3, -- screen background + focus = COLOR_THEME_FOCUS, + edit = COLOR_THEME_EDIT, + active = COLOR_THEME_ACTIVE, +} + +function M.getVer() + return app_ver +end + +-- Return true if the first arg matches any of the following args +function M.match(x, ...) + for i, y in ipairs({ ... }) do + if x == y then + return true + end + end + return false +end + + +-- Create a new GUI object with interactive screen elements +function M.newGUI() + local gui = { + x = 0, + y = 0, + editable = true, + } + + local _ = {} -- internal members + _.handles = { } + _.elements = { } + _.focus = 1 + _.scrolling = false + _.lastEvent = 0 + + + function _.lcdSizeTextFixed(txt, font_size) + local ts_w, ts_h = lcd.sizeText(txt, font_size) + + local v_offset = 0 + if font_size == M.FONT_SIZES.FONT_38 then + v_offset = -11 + elseif font_size == M.FONT_SIZES.FONT_16 then + v_offset = -5 + elseif font_size == M.FONT_SIZES.FONT_12 then + v_offset = -4 + elseif font_size == M.FONT_SIZES.FONT_8 then + v_offset = -3 + elseif font_size == M.FONT_SIZES.FONT_6 then + v_offset = 0 + end + return ts_w, ts_h +2*v_offset, v_offset + end + + -- Translate coordinates for sub-GUIs + function gui.translate(x, y) + if gui.parent then + x, y = gui.parent.translate(x, y) + end + return gui.x + x, gui.y + y + end + + -- Replace lcd functions to translate by gui offset + function gui.drawCircle(x, y, r, flags) + x, y = gui.translate(x, y) + lcd.drawCircle(x, y, r, flags) + end + + function gui.drawFilledCircle(x, y, r, flags) + x, y = gui.translate(x, y) + lcd.drawFilledCircle(x, y, r, flags) + end + + function gui.drawLine(x1, y1, x2, y2, pattern, flags) + x1, y1 = gui.translate(x1, y1) + x2, y2 = gui.translate(x2, y2) + lcd.drawLine(x1, y1, x2, y2, pattern, flags) + end + + function gui.drawRectangle(x, y, w, h, flags, t) + x, y = gui.translate(x, y) + lcd.drawRectangle(x, y, w, h, flags, t) + end + + function gui.drawFilledRectangle(x, y, w, h, flags, opacity) + x, y = gui.translate(x, y) + lcd.drawFilledRectangle(x, y, w, h, flags, opacity) + end + + function gui.drawTriangle(x1, y1, x2, y2, x3, y3, flags) + x1, y1 = gui.translate(x1, y1) + x2, y2 = gui.translate(x2, y2) + x3, y3 = gui.translate(x3, y3) + lcd.drawTriangle(x1, y1, x2, y2, x3, y3, flags) + end + + function gui.drawFilledTriangle(x1, y1, x2, y2, x3, y3, flags) + x1, y1 = gui.translate(x1, y1) + x2, y2 = gui.translate(x2, y2) + x3, y3 = gui.translate(x3, y3) + lcd.drawFilledTriangle(x1, y1, x2, y2, x3, y3, flags) + end + + function gui.drawText(x, y, text, flags, inversColor) + x, y = gui.translate(x, y) + local ts_w, ts_h, v_offset = _.lcdSizeTextFixed(text, M.FONT_SIZES.FONT_8) + lcd.drawText(x, y + v_offset, text, flags, inversColor) + --lcd.drawText(x, y, text, flags, inversColor) + end + + function gui.drawTextLines(x, y, w, h, text, flags) + x, y = gui.translate(x, y) + lcd.drawTextLines(x, y, w, h, text, flags) + end + + function gui.drawNumber(x, y, value, flags, inversColor) + x, y = gui.translate(x, y) + lcd.drawNumber(x, y, value, flags, inversColor) + end + + function gui.drawTimer(x, y, value, flags, inversColor) + x, y = gui.translate(x, y) + lcd.drawTimer(x, y, value, flags, inversColor) + end + + -- The default callBack + function _.doNothing() + end + + -- The default onChangeValue + function _.onChangeDefault(delta, self) + return self.value + delta + end + + -- Adjust text according to horizontal alignment + function _.align(x, w, flags) + if bit32.band(flags, RIGHT) == RIGHT then + return x + w + elseif bit32.band(flags, CENTER) == CENTER then + return x + w / 2 + else + return x + end + end -- align(...) + + -- Draw border around focused elements + local function drawFocus(x, y, w, h, color) + -- Not necessary if there is only one element... + if #_.elements == 1 then + return + end + color = color or M.colors.focus + gui.drawRectangle(x - 2, y - 2, w + 4, h + 4, color, 2) + end -- drawFocus(...) + + -- Move focus to another element + local function moveFocus(delta) + local count = 0 -- Prevent infinite loop + repeat + _.focus = _.focus + delta + if _.focus > #_.elements then + _.focus = 1 + elseif _.focus < 1 then + _.focus = #_.elements + end + count = count + 1 + until not (_.elements[_.focus].disabled or _.elements[_.focus].hidden) or count > #_.elements + end -- moveFocus(...) + + -- Moved the focused element + function gui.moveFocused(delta) + if delta > 0 then + delta = 1 + elseif delta < 0 then + delta = -1 + end + local idx = _.focus + delta + if idx >= 1 and idx <= #_.elements then + _.elements[_.focus], _.elements[idx] = _.elements[idx], _.elements[_.focus] + _.focus = idx + end + end + + -- Add an element and return it to the client + local function addElement(element, x, y, w, h) + if not element.covers then + function element.covers(p, q) + return (x <= p and p <= x + w and y <= q and q <= y + h) + end + end + + _.elements[#_.elements+1] = element + return element + end -- addElement(...) + + -- Add temporary BLINK or INVERS flags + local function getFlags(element) + local flags = element.flags + if element.blink then flags = bit32.bor(flags or 0, BLINK) end + if element.invers then flags = bit32.bor(flags or 0, INVERS) end + return flags + end + + -- Set an event handler + function gui.setEventHandler(event, f) + _.handles[event] = f + end + + -- Show prompt + function gui.showPrompt(prompt) + M.prompt = prompt + end + + -- Dismiss prompt + function gui.dismissPrompt() + M.prompt = nil + end + + ----------------------------------------------------------------------------------------------- + + -- Run an event cycle + function gui.run(event, touchState) + gui.draw(false) + if event ~= nil then + gui.onEvent(event, touchState) + end + _.lastEvent = event + end -- run(...) + + ----------------------------------------------------------------------------------------------- + + function gui.draw(focused) + if gui.fullScreenRefresh then + gui.fullScreenRefresh() + end + if focused then + if gui.parent.editing then + drawFocus(0, 0, gui.w, gui.h, M.colors.edit) + else + drawFocus(0, 0, gui.w, gui.h) + end + end + local guiFocus = not gui.parent or (focused and gui.parent.editing) + for idx, element in ipairs(_.elements) do + -- Clients may provide an update function for elements + if element.onUpdate then + element.onUpdate(element) + end + if not element.hidden then + element.draw(_.focus == idx and guiFocus) + end + end + end -- draw() + + ----------------------------------------------------------------------------------------------- + + function gui.onEvent(event, touchState) + -- Make sure that focused element is active + if (_.elements[_.focus].disabled or _.elements[_.focus].hidden) then + moveFocus(1) + return + end + -- Is there an active prompt? + if M.prompt and not M.showingPrompt then + M.showingPrompt = true + M.prompt.run(event, touchState) + M.showingPrompt = false + return + end + + if event == 0 then + return + end + + if gui.parent and not gui.parent.editing then + if event == EVT_VIRTUAL_ENTER then + gui.parent.editing = true + end + return + end + + -- non-zero event; process it + -- Translate touch coordinates if offset + if touchState then + touchState.x = touchState.x - gui.x + touchState.y = touchState.y - gui.y + if touchState.startX then + touchState.startX = touchState.startX - gui.x + touchState.startY = touchState.startY - gui.y + end + -- "Un-convert" ENTER to TAP + if event == EVT_VIRTUAL_ENTER then + event = EVT_TOUCH_TAP + end + end + + -- ETX 2.8 rc 4 bug fix + if _.scrolling and event == EVT_VIRTUAL_ENTER_LONG then + return + end + -- If we put a finger down on a menu item and immediately slide, then we can scroll + if event == EVT_TOUCH_SLIDE then + if not _.scrolling then + return + end + else + _.scrolling = false + end + + -- "Pre-processing" of touch events to simplify subsequent handling and support scrolling etc. + if event == EVT_TOUCH_FIRST then + if _.elements[_.focus].covers(touchState.x, touchState.y) then + _.scrolling = true + else + if gui.editing then + return + else + -- Did we touch another element? + for idx, element in ipairs(_.elements) do + if not (element.disabled or element.hidden) and element.covers(touchState.x, touchState.y) then + _.focus = idx + _.scrolling = true + end + end + end + end + elseif event == EVT_TOUCH_TAP or (event == EVT_TOUCH_BREAK and _.lastEvent == EVT_TOUCH_FIRST) then + if _.elements[_.focus].covers(touchState.x, touchState.y) then + -- Convert TAP on focused element to ENTER + event = EVT_VIRTUAL_ENTER + elseif gui.editing then + -- Convert a TAP off the element being edited to EXIT + event = EVT_VIRTUAL_EXIT + end + end + + if gui.editing then -- Send the event directly to the element being edited + _.elements[_.focus].onEvent(event, touchState) + elseif event == EVT_VIRTUAL_NEXT then -- Move focus + moveFocus(1) + elseif event == EVT_VIRTUAL_PREV then + moveFocus(-1) + elseif event == EVT_VIRTUAL_EXIT and gui.parent then + gui.parent.editing = false + else + if _.handles[event] then + -- Is it being handled? Handler can modify event + event = _.handles[event](event, touchState) + -- If handler returned false or nil, then we are done + if not event then + return + end + end + _.elements[_.focus].onEvent(event, touchState) + end + end -- onEvent(...) + + ----------------------------------------------------------------------------------------------- + + -- Create a text label + function gui.label(x, y, w, h, title, flags) + local self = { + title = title, + flags = bit32.bor(flags or M.flags, VCENTER, M.colors.primary1), + disabled = true, + hidden= false, + } + + function self.draw(focused) + local flags = getFlags(self) + gui.drawText(_.align(x, w, flags), y + h / 2, self.title, flags) + end + + -- We should not ever onEvent, but just in case... + function self.onEvent(event, touchState) + self.disabled = true + moveFocus(1) + end + + function self.covers(p, q) + return false + end + + addElement(self, x, y, w, h) + return self + end -- label(...) + + ----------------------------------------------------------------------------------------------- + + -- Create a text label lines + function gui.labelLines(x, y, w, h, title, flags) + local self = { + title = title, + flags = bit32.bor(flags or M.flags, VCENTER, M.colors.primary1), + disabled = true, + hidden= false, + } + + function self.draw(focused) + local flags = getFlags(self) + gui.drawTextLines(_.align(x, w, flags), y , w, h, self.title, flags) + end + + -- We should not ever onEvent, but just in case... + function self.onEvent(event, touchState) + self.disabled = true + moveFocus(1) + end + + function self.covers(p, q) + return false + end + + addElement(self, x, y, w, h) + return self + end -- label(...) + + ----------------------------------------------------------------------------------------------- + + -- Create a button to trigger a function + function gui.button(x, y, w, h, title, callBack, flags) + local self = { + title = title, + callBack = callBack or _.doNothing, + flags = bit32.bor(flags or M.flags, CENTER, VCENTER), + disabled = false, + hidden= false + } + + function self.draw(focused) + if focused then + drawFocus(x, y, w, h) + end + + gui.drawFilledRectangle(x, y, w, h, M.colors.primary2) + gui.drawRectangle(x, y, w, h, M.colors.secondary2) + gui.drawText(x + w / 2, y + h / 2, self.title, bit32.bor(M.colors.secondary1, self.flags)) + + if self.disabled then + gui.drawFilledRectangle(x, y, w, h, GREY, 7) + end + end + + function self.onEvent(event, touchState) + if event == EVT_VIRTUAL_ENTER then + return self.callBack(self) + end + end + + addElement(self, x, y, w, h) + return self + end -- button(...) + + ----------------------------------------------------------------------------------------------- + + -- Create a toggle button that turns on/off. callBack gets true/false + function gui.toggleButton(x, y, w, h, title, value, callBack, flags) + local self = { + title = title, + value = value, + callBack = callBack or _.doNothing, + flags = bit32.bor(flags or M.flags, CENTER, VCENTER), + disabled = false, + hidden= false + } + + function self.draw(focused) + local fg = M.colors.primary3 + local bg = M.colors.primary2 + local border = M.colors.secondary2 + + if self.value then + fg = M.colors.secondary3 + bg = M.colors.secondary1 + border = M.colors.focus + end + + if focused then + drawFocus(x, y, w, h, border) + end + + gui.drawFilledRectangle(x, y, w, h, bg) + gui.drawRectangle(x, y, w, h, border) + gui.drawText(x + w / 2, y + h / 2, self.title, bit32.bor(fg, self.flags)) + + if self.disabled then + gui.drawFilledRectangle(x, y, w, h, GREY, 7) + end + end + + function self.onEvent(event, touchState) + if event == EVT_VIRTUAL_ENTER then + self.value = not self.value + return self.callBack(self) + end + end + + addElement(self, x, y, w, h) + return self + end -- toggleButton(...) + + ----------------------------------------------------------------------------------------------- + + -- Create a number that can be edited + function gui.number(x, y, w, h, value, onChangeValue, flags, min, max) + local self = { + value = value, + onChangeValue = onChangeValue or _.onChangeDefault, + flags = bit32.bor(flags or M.flags, VCENTER), + editable = true, + disabled = false, + hidden= false, + min_val = min or 0, + max_val = max or 100, + } + + local d0 + + function self.draw(focused) + local flags = getFlags(self) + local fg = M.colors.primary1 + + if focused then + drawFocus(x, y, w, h) + + if gui.editing then + fg = M.colors.primary2 + gui.drawFilledRectangle(x, y, w, h, M.colors.edit) + end + end + if type(self.value) == "string" then + gui.drawText(_.align(x, w, flags), y + h / 2, self.value, bit32.bor(fg, flags)) + else + gui.drawNumber(_.align(x, w, flags), y + h / 2, self.value, bit32.bor(fg, flags)) + end + end + + function self.onEvent(event, touchState) + if gui.editing then + if event == EVT_VIRTUAL_ENTER then + gui.editing = false + elseif event == EVT_VIRTUAL_EXIT then + self.value = value + gui.editing = false + elseif event == EVT_VIRTUAL_INC then + if self.value < self.max_val then + self.value = self.onChangeValue(1, self) + end + elseif event == EVT_VIRTUAL_DEC then + if self.value > self.min_val then + self.value = self.onChangeValue(-1, self) + end + elseif event == EVT_TOUCH_FIRST then + d0 = 0 + elseif event == EVT_TOUCH_SLIDE then + local d = math.floor((touchState.startY - touchState.y) / 20 + 0.5) + if d ~= d0 then + self.value = self.onChangeValue(d - d0, self) + d0 = d + end + end + elseif event == EVT_VIRTUAL_ENTER then + value = self.value + gui.editing = true + end + end -- onEvent(...) + + addElement(self, x, y, w, h) + return self + end -- number(...) + + ----------------------------------------------------------------------------------------------- + + -- Create a display of current time on timer[tmr] + -- Set timer.value to show a different value + function gui.timer(x, y, w, h, tmr, onChangeValue, flags) + local self = { + tmr = tmr, + onChangeValue = onChangeValue or _.onChangeDefault, + flags = bit32.bor(flags or M.flags, VCENTER), + disabled = false, + hidden= false, + editable = true + } + local value + local d0 + + function self.draw(focused) + local flags = getFlags(self) + local fg = M.colors.primary1 + -- self.value overrides the timer value + local value = self.value or model.getTimer(self.tmr).value + + if focused then + drawFocus(x, y, w, h) + + if gui.editing then + fg = M.colors.primary2 + gui.drawFilledRectangle(x, y, w, h, M.colors.edit) + end + end + if type(value) == "string" then + gui.drawText(_.align(x, w, flags), y + h / 2, value, bit32.bor(fg, flags)) + else + gui.drawTimer(_.align(x, w, flags), y + h / 2, value, bit32.bor(fg, flags)) + end + end + + function self.onEvent(event, touchState) + if gui.editing then + if event == EVT_VIRTUAL_ENTER then + if not value and self.tmr then + local tblTmr = model.getTimer(self.tmr) + tblTmr.value = self.value + model.setTimer(self.tmr, tblTmr) + self.value = nil + end + gui.editing = false + elseif event == EVT_VIRTUAL_EXIT then + self.value = value + gui.editing = false + elseif event == EVT_VIRTUAL_INC then + self.value = self.onChangeValue(1, self) + elseif event == EVT_VIRTUAL_DEC then + self.value = self.onChangeValue(-1, self) + elseif event == EVT_TOUCH_FIRST then + d0 = 0 + elseif event == EVT_TOUCH_SLIDE then + local d = math.floor((touchState.startY - touchState.y) / 20 + 0.5) + if d ~= d0 then + self.value = self.onChangeValue(d - d0, self) + d0 = d + end + end + elseif event == EVT_VIRTUAL_ENTER then + if self.value then + value = self.value + elseif self.tmr then + self.value = model.getTimer(self.tmr).value + value = nil + end + gui.editing = true + end + end -- onEvent(...) + + addElement(self, x, y, w, h) + return self + end -- timer(...) + + ----------------------------------------------------------------------------------------------- + + function gui.menu(x, y, w, h, items, callBack, flags) + local self = { + items = items or { "No items!" }, + flags = bit32.bor(flags or M.flags, VCENTER), + disabled = false, + hidden= false, + editable = true, + selected = 1 + } + local selected = 1 + local firstVisible = 1 + local firstVisibleScrolling + local moving = 0 + local lh = select(2, lcd.sizeText("", self.flags)) + local visibleCount = math.floor(h / lh) + local killEvt + + callBack = callBack or _.doNothing + + local function setFirstVisible(v) + firstVisible = v + firstVisible = math.max(1, firstVisible) + firstVisible = math.min(#self.items - visibleCount + 1, firstVisible) + end + + local function adjustScroll() + if selected >= firstVisible + visibleCount then + firstVisible = selected - visibleCount + 1 + elseif selected < firstVisible then + firstVisible = selected + end + end + + function self.draw(focused) + local flags = getFlags(self) + local visibleCount = math.min(visibleCount, #self.items) + local sel + local bgColor + + if focused and gui.editing then + bgColor = M.colors.edit + else + selected = self.selected + bgColor = M.colors.focus + end + + for i = 0, visibleCount - 1 do + local j = firstVisible + i + local y = y + i * lh + + if j == selected then + gui.drawFilledRectangle(x, y, w, lh, bgColor) + gui.drawText(_.align(x, w, flags), y + lh / 2, self.items[j], bit32.bor(M.colors.primary2, flags)) + else + gui.drawText(_.align(x, w, flags), y + lh / 2, self.items[j], bit32.bor(M.colors.primary1, flags)) + end + end + + if focused then + drawFocus(x, y, w, h) + end + end -- draw() + + function self.onEvent(event, touchState) + local visibleCount = math.min(visibleCount, #self.items) + + if moving ~= 0 then + if M.match(event, EVT_TOUCH_FIRST, EVT_VIRTUAL_ENTER, EVT_VIRTUAL_EXIT) then + moving = 0 + event = 0 + else + setFirstVisible(firstVisible + moving) + end + end + + if event ~= 0 then + -- This hack is needed because killEvents does not seem to work + if killEvt then + killEvt = false + if event == EVT_VIRTUAL_ENTER then + event = 0 + end + end + + -- If we touch it, then start editing immediately + if touchState then + gui.editing = true + end + + if event == EVT_TOUCH_SLIDE then + if _.scrolling then + if touchState.swipeUp then + moving = 1 + elseif touchState.swipeDown then + moving = -1 + elseif touchState.startX then + setFirstVisible(firstVisibleScrolling + math.floor((touchState.startY - touchState.y) / lh + 0.5)) + end + end + else + _.scrolling = false + + if event == EVT_TOUCH_FIRST then + _.scrolling = true + firstVisibleScrolling = firstVisible + elseif M.match(event, EVT_VIRTUAL_NEXT, EVT_VIRTUAL_PREV) then + if event == EVT_VIRTUAL_NEXT then + selected = math.min(#self.items, selected + 1) + elseif event == EVT_VIRTUAL_PREV then + selected = math.max(1, selected - 1) + end + adjustScroll() + elseif event == EVT_VIRTUAL_ENTER then + if gui.editing then + if touchState then + selected = firstVisible + math.floor((touchState.y - y) / lh) + end + + gui.editing = false + self.selected = selected + callBack(self) + else + gui.editing = true + selected = self.selected + adjustScroll() + end + elseif event == EVT_VIRTUAL_EXIT then + gui.editing = false + end + end + end + end -- onEvent(...) + + addElement(self, x, y, w, h) + return self + end -- menu(...) + + ----------------------------------------------------------------------------------------------- + + function gui.dropDown(x, y, w, h, items, selected, callBack, flags) + callBack = callBack or _.doNothing + flags = flags or M.flags + + local self + local showingMenu + local drawingMenu + local dropDown = M.newGUI() + local lh = select(2, lcd.sizeText("", flags)) + local height = math.min(0.75 * LCD_H, #items * lh) + local top = (LCD_H - height) / 2 + + dropDown.x = gui.translate(0, 0) + top = math.min(top, y) + top = math.max(top, y + h - height) + + local function dismissMenu() + showingMenu = false + gui.dismissPrompt() + end + + function dropDown.fullScreenRefresh() + if not dropDown.editing then + dismissMenu() + return + end + dropDown.drawFilledRectangle(x, top, w, height, M.colors.primary2) + dropDown.drawRectangle(x - 2, top - 2, w + 4, height + 4, M.colors.primary1, 2) + drawingMenu = true + end + + local function onMenu(menu) + dismissMenu() + callBack(self) + end + + self = dropDown.menu(x, top, w, height, items, onMenu, flags) + self.selected = selected + local drawMenu = self.draw + + function self.draw(focused) + if drawingMenu then + drawingMenu = false + drawMenu(focused) + else + local flags = bit32.bor(VCENTER, M.colors.primary1, getFlags(self)) + + if focused then + drawFocus(x, y, w, h) + end + gui.drawText(_.align(x, w, flags), y + h / 2, self.items[self.selected], flags) + local dd = lh / 2 + local yy = y + (h - dd) / 2 + local xx = (x-5) + w - 1.15 * dd + gui.drawTriangle(x-5 + w, yy, (x-5 + w + xx) / 2, yy + dd, xx, yy, M.colors.primary1) + end + end + + local onMenu = self.onEvent + + function self.onEvent(event, touchState) + if showingMenu then + onMenu(event, touchState) + elseif event == EVT_VIRTUAL_ENTER then + -- Show drop down and let it take over while active + showingMenu = true + dropDown.onEvent(event) + gui.showPrompt(dropDown) + else + end + end + + local coverMenu = self.covers + + function self.covers(p, q) + if showingMenu then + return coverMenu(p, q) + else + return (x <= p and p <= x + w and y <= q and q <= y + h) + end + end + + addElement(self, x, y, w, h) + return self + end -- dropDown(...) + + ----------------------------------------------------------------------------------------------- + + function gui.horizontalSlider(x, y, w, value, min, max, delta, callBack) + local self = { + value = value, + min = min, + max = max, + delta = delta, + callBack = callBack or _.doNothing, + disabled = false, + hidden= false, + editable = true + } + + function self.draw(focused) + local xdot = x + w * (self.value - self.min) / (self.max - self.min) + + local colorBar = M.colors.primary3 + local colorDot = M.colors.primary2 + local colorDotBorder = M.colors.primary3 + + if focused then + colorDotBorder = M.colors.active + if gui.editing or _.scrolling then + colorBar = M.colors.primary1 + colorDot = M.colors.edit + end + end + + gui.drawFilledRectangle(x, y - 2, w, 5, colorBar) + gui.drawFilledCircle(xdot, y, M.SLIDER_DOT_RADIUS, colorDot) + for i = -1, 1 do + gui.drawCircle(xdot, y, M.SLIDER_DOT_RADIUS + i, colorDotBorder) + end + end + + function self.onEvent(event, touchState) + local v0 = self.value + + if gui.editing then + if M.match(event, EVT_VIRTUAL_ENTER, EVT_VIRTUAL_EXIT) then + gui.editing = false + elseif event == EVT_VIRTUAL_INC then + self.value = math.min(self.max, self.value + self.delta) + elseif event == EVT_VIRTUAL_DEC then + self.value = math.max(self.min, self.value - self.delta) + end + elseif event == EVT_VIRTUAL_ENTER then + gui.editing = true + end + + if event == EVT_TOUCH_SLIDE then + local value = self.min + (self.max - self.min) * (touchState.x - x) / w + value = math.min(self.max, value) + value = math.max(self.min, value) + self.value = self.min + self.delta * math.floor((value - self.min) / self.delta + 0.5) + end + + if v0 ~= self.value then + self.callBack(self) + end + end + + function self.covers(p, q) + local xdot = x + w * (self.value - self.min) / (self.max - self.min) + return ((p - xdot) ^ 2 + (q - y) ^ 2 <= 2 * M.SLIDER_DOT_RADIUS ^ 2) + end + + addElement(self) + return self + end -- horizontalSlider(...) + + ----------------------------------------------------------------------------------------------- + + function gui.verticalSlider(x, y, h, value, min, max, delta, callBack) + local self = { + value = value, + min = min, + max = max, + delta = delta, + callBack = callBack or _.doNothing, + disabled = false, + hidden= false, + editable = true + } + + function self.draw(focused) + local ydot = y + h * (1 - (self.value - self.min) / (self.max - self.min)) + + local colorBar = M.colors.primary3 + local colorDot = M.colors.primary2 + local colorDotBorder = M.colors.primary3 + + if focused then + colorDotBorder = M.colors.active + if gui.editing or _.scrolling then + colorBar = M.colors.primary1 + colorDot = M.colors.edit + end + end + + gui.drawFilledRectangle(x - 2, y, 5, h, colorBar) + gui.drawFilledCircle(x, ydot, M.SLIDER_DOT_RADIUS, colorDot) + for i = -1, 1 do + gui.drawCircle(x, ydot, M.SLIDER_DOT_RADIUS + i, colorDotBorder) + end + end + + function self.onEvent(event, touchState) + local v0 = self.value + + if gui.editing then + if M.match(event, EVT_VIRTUAL_ENTER, EVT_VIRTUAL_EXIT) then + gui.editing = false + elseif event == EVT_VIRTUAL_INC then + self.value = math.min(self.max, self.value + self.delta) + elseif event == EVT_VIRTUAL_DEC then + self.value = math.max(self.min, self.value - self.delta) + end + elseif event == EVT_VIRTUAL_ENTER then + gui.editing = true + end + + if event == EVT_TOUCH_SLIDE then + local value = self.max - (self.max - self.min) * (touchState.y - y) / h + value = math.min(self.max, value) + value = math.max(self.min, value) + self.value = self.min + self.delta * math.floor((value - self.min) / self.delta + 0.5) + end + + if v0 ~= self.value then + self.callBack(self) + end + end + + function self.covers(p, q) + local ydot = y + h * (1 - (self.value - self.min) / (self.max - self.min)) + return ((p - x) ^ 2 + (q - ydot) ^ 2 <= 2 * M.SLIDER_DOT_RADIUS ^ 2) + end + + addElement(self) + return self + end -- verticalSlider(...) + + ----------------------------------------------------------------------------------------------- + + -- Create a custom element + function gui.custom(self, x, y, w, h) + self.gui = gui + self.lib = M + + function self.drawFocus(color) + drawFocus(self.x or x, self.y or y, self.w or w, self.h or h, color) + end + + -- Must be implemented by the client + if not self.draw then + function self.draw(focused) + gui.drawText(x, y, "draw(focused) missing") + if focused then + drawFocus(x, y, w, h) + end + end + end + + -- Must be implemented by the client + if not self.onEvent then + function self.onEvent() + playTone(200, 200, 0, PLAY_NOW) + end + end + + addElement(self, x, y, w, h) + return self + end + + ----------------------------------------------------------------------------------------------- + + -- Create a nested gui + function gui.gui(x, y, w, h) + local self = M.newGUI() + self.parent = gui + self.editing = false + self.x, self.y, self.w, self.h = x, y, w, h + + function self.covers(p, q) + return (self.x <= p and p <= self.x + self.w and self.y <= q and q <= self.y + self.h) + end + + addElement(self, x, y, w, h) + return self + end + + + ----------------------------------------------------------------------------------------------- + return gui + +end -- gui(...) + +return M diff --git a/sdcard/c480x272/WIDGETS/SoarETX/main.lua b/sdcard/c480x272/WIDGETS/SoarETX/main.lua index fe3c533..3ec6370 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/main.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/main.lua @@ -21,9 +21,9 @@ --------------------------------------------------------------------------- local options = { - { "Version", VALUE, 1, 1, 99 }, + { "Version", VALUE, 1, 1, 2 }, { "FileName", STRING, "" }, - { "Type", STRING, "" } + { "Type", STRING, "" } -- F3K|F3K_TRAD|F3K_FH|F3K_RE|F3J|F5J } local soarGlobals @@ -34,21 +34,21 @@ local rxBatNxtCheck = 0 function rxBatCheck() local now = getTime() - + if now < rxBatNxtCheck then return end - + rxBatNxtCheck = now + 100 - + local rxBatSrc = getFieldInfo("Cels") if not rxBatSrc then rxBatSrc = getFieldInfo("RxBt") end if not rxBatSrc then rxBatSrc = getFieldInfo("A1") end if not rxBatSrc then rxBatSrc = getFieldInfo("A2") end - + if rxBatSrc then soarGlobals.battery = getValue(rxBatSrc.id) - + if type(soarGlobals.battery) == "table" then for i = 2, #soarGlobals.battery do soarGlobals.battery[1] = math.min(soarGlobals.battery[1], soarGlobals.battery[i]) @@ -85,7 +85,7 @@ local function GetCurve(crvIndex) if #oldTbl.y == N then -- Normal Behaviour return oldTbl end - + -- Work arround the bug of GetCurve in some versions (2.8.3) of ETX if #oldTbl.y == N - 1 then local newTbl = { } @@ -110,10 +110,13 @@ local function init() batteryParameter = 1, getCurve = GetCurve } + soarGlobals.libGUI = loadScript("/WIDGETS/SoarETX/libgui.lua")() + local gui = soarGlobals.libGUI.newGUI() + -- Functions to handle persistent model parameters stored in curve 32 local parameterCurve = GetCurve(31) - + if not parameterCurve then error("Curve #32 is missing! It is used to store persistent model parameters for Lua.") end @@ -133,7 +136,7 @@ local function create(zone, options) if not soarGlobals then init() end - + local widget = { zone = zone, options = options @@ -145,7 +148,7 @@ end local function update(widget, options) if options.Version ~= widget.options.Version or options.FileName ~= widget.options.FileName then local zone = widget.zone - + -- Erase all fields in widget local keys = { } for key in pairs(widget) do @@ -154,7 +157,7 @@ local function update(widget, options) for i, key in ipairs(keys) do widget[key] = nil end - + widget.zone = zone widget.options = options Load(widget) @@ -178,10 +181,10 @@ local function background(widget) end return { - name = "SoarETX", - create = create, - refresh = refresh, - options = options, - update = update, + name = "SoarETX", + create = create, + refresh = refresh, + options = options, + update = update, background = background -} \ No newline at end of file +}