Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- function scanPeripherals()
- term.setTextColor(colors.cyan)
- print("Scanning for peripherals...\n")
- local sides = {"top", "bottom", "left", "right", "front", "back"}
- local foundAny = false
- for _, side in ipairs(sides) do
- if peripheral.isPresent(side) then
- foundAny = true
- local name = peripheral.getType(side)
- term.setTextColor(colors.lime)
- print("[FOUND] " .. name .. " at " .. side)
- else
- term.setTextColor(colors.red)
- print("[NOT FOUND] No peripheral at " .. side)
- end
- end
- if not foundAny then
- term.setTextColor(colors.yellow)
- print("\nNo peripherals found.")
- end
- term.setTextColor(colors.white) -- Reset color
- end
- scanPeripherals()
- -- QuartzDE - A Basic Desktop Environment for CraftOS (CC: Tweaked)
- -- Features:
- -- • Draggable & Resizable Windows with a full window frame (title bar, close and resize handles)
- -- • Programs Menu (with an "Exit Desktop" option)
- -- • Program windows run inside an inner content area so that the frame remains intact.
- -- • For games, if they don’t naturally render well in a window, they are centered
- -- and a "[Close Game]" button is provided in the content area.
- -- Credits: Made by Orion on 16th March 25
- -- List of available programs
- local programs = {
- {name = "redirection", path = "redirection"},
- {name = "worm", path = "worm"},
- {name = "About QuartzDE", path = "about"},
- {name = "Exit Desktop", path = "exit"}
- }
- -- Global variables for window management
- local windows = {}
- local windowID = 0
- local draggingWindow = nil
- local resizingWindow = nil
- local dragOffsetX, dragOffsetY = 0, 0
- local screenW, screenH = term.getSize()
- local exitRequested = false
- local minWidth, minHeight = 20, 5
- math.randomseed(os.time())
- --------------------------------------------------
- -- Window Manager Functions
- --------------------------------------------------
- -- createWindow creates a new window record.
- -- The parameter 'content' is a function(innerWin, win) that draws the inner content.
- local function createWindow(title, x, y, w, h, content)
- windowID = windowID + 1
- local win = {
- id = windowID,
- title = title or "Untitled",
- x = x or 5,
- y = y or 5,
- w = w or 30,
- h = h or 10,
- visible = true,
- content = content, -- function(innerWindow, win) for inner drawing
- programStarted = false, -- used for program windows so they run only once
- programFinished = false, -- becomes true when the program has finished running
- waitForKey = false, -- if true, the window is waiting for a key to close
- closeButton = nil -- for game windows: absolute coords for the [Close Game] button
- }
- table.insert(windows, win)
- return win
- end
- -- drawDesktop clears the background.
- local function drawDesktop()
- term.setBackgroundColor(colors.blue)
- term.clear()
- end
- -- drawWindow draws a complete window:
- -- 1. Creates the outer frame (using a dedicated window) and draws:
- -- - A title bar (line 1) with the window title and a frame close button ("X").
- -- - A resize handle ("+") at the bottom–right corner.
- -- 2. Then creates an inner content area (a sub–window) that occupies the region
- -- inside the frame (leaving a 1–cell border) and calls win.content(innerWin, win) if provided.
- local function drawWindow(win)
- local frame = window.create(term.current(), win.x, win.y, win.w, win.h)
- frame.setBackgroundColor(colors.gray)
- frame.clear()
- -- Draw title bar on first line of the frame
- frame.setBackgroundColor(colors.lightGray)
- frame.setTextColor(colors.black)
- frame.setCursorPos(1, 1)
- frame.write(string.rep(" ", win.w))
- frame.setCursorPos(2, 1)
- frame.write(win.title)
- -- Draw close button ("X") in top–right corner of the frame
- local closeX = win.w - 1
- frame.setCursorPos(closeX, 1)
- frame.setTextColor(colors.red)
- frame.write("X")
- -- Draw resize handle ("+") at bottom–right corner of the frame
- frame.setCursorPos(win.w, win.h)
- frame.setTextColor(colors.white)
- frame.write("+")
- -- Create inner content area.
- -- The inner window is inset by 1 cell on left and top and leaves a border.
- local inner = window.create(frame, 2, 2, win.w - 2, win.h - 2)
- if win.content then
- win.content(inner, win)
- end
- frame.redraw()
- inner.redraw()
- end
- -- Helper functions for mouse hit detection on the outer frame:
- local function isInWindow(win, mx, my)
- return (mx >= win.x and mx < win.x + win.w) and (my >= win.y and my < win.y + win.h)
- end
- local function isInTitleBar(win, mx, my)
- return isInWindow(win, mx, my) and (my == win.y)
- end
- local function isInCloseButton(win, mx, my)
- return (my == win.y) and (mx >= win.x + win.w - 2 and mx < win.x + win.w)
- end
- local function isInResizeHandle(win, mx, my)
- return (mx >= win.x + win.w - 2 and mx < win.x + win.w) and (my >= win.y + win.h - 1 and my < win.y + win.h)
- end
- -- Bring a window to the front (end of the windows table).
- local function bringToFront(index)
- local win = table.remove(windows, index)
- table.insert(windows, win)
- end
- --------------------------------------------------
- -- Taskbar & Programs Menu Functions
- --------------------------------------------------
- local function drawTaskbar()
- local w, h = term.getSize()
- term.setBackgroundColor(colors.gray)
- term.setTextColor(colors.white)
- term.setCursorPos(1, h)
- term.write(string.rep(" ", w)) -- Clear the taskbar line
- term.setCursorPos(1, h)
- term.write(" [Programs] ")
- end
- -- showProgramMenu displays a simple menu above the taskbar.
- -- It returns the selected program (a table) or nil if canceled.
- local function showProgramMenu()
- local menuWidth = 20
- local menuHeight = #programs
- local w, h = term.getSize()
- local startX = 1
- local startY = h - menuHeight - 1
- local menuWin = window.create(term.current(), startX, startY, menuWidth, menuHeight)
- menuWin.setBackgroundColor(colors.lightGray)
- menuWin.clear()
- for i, item in ipairs(programs) do
- menuWin.setCursorPos(2, i)
- menuWin.setTextColor(colors.black)
- menuWin.write(item.name)
- end
- menuWin.redraw()
- local selection = nil
- local event, button, mx, my = os.pullEvent("mouse_click")
- if mx >= startX and mx < startX + menuWidth and my >= startY and my < startY + menuHeight then
- local index = my - startY + 1
- selection = programs[index]
- end
- menuWin.clear()
- menuWin = nil
- return selection
- end
- --------------------------------------------------
- -- Program Launcher: Creates a window for the program.
- --------------------------------------------------
- local function runProgram(prog)
- if prog.path == "exit" then
- exitRequested = true
- return
- end
- local x, y, w, h
- if prog.path == "about" then
- w, h = 40, 12
- x = math.floor((screenW - w) / 2) + 1
- y = math.floor((screenH - h) / 2) + 1
- else
- w, h = 50, 15
- x = math.floor((screenW - w) / 2) + 1
- y = math.floor((screenH - h) / 2) + 1
- end
- local contentFunction = nil
- if prog.path == "about" then
- -- The About window draws credits in the inner content area.
- contentFunction = function(inner, win)
- inner.setBackgroundColor(colors.black)
- inner.clear()
- inner.setCursorPos(1, 1)
- inner.setTextColor(colors.white)
- inner.write("QuartzDE Desktop Environment")
- inner.setCursorPos(1, 2)
- inner.write("Made by Orion")
- inner.setCursorPos(1, 3)
- inner.write("Made on 16th March 25")
- inner.setCursorPos(1, 5)
- inner.write("Press any key to close")
- win.waitForKey = true
- inner.redraw()
- end
- else
- -- For games (or other programs), run them inside the inner window.
- contentFunction = function(inner, win)
- if not win.programStarted then
- win.programStarted = true
- inner.setBackgroundColor(colors.black)
- inner.clear()
- local oldTerm = term.redirect(inner)
- shell.run(prog.path)
- term.redirect(oldTerm)
- win.programFinished = true
- end
- -- Draw a [Close Game] button in the inner area (bottom center).
- local cw = win.w - 2 -- inner width
- local ch = win.h - 2 -- inner height
- local buttonText = "[Close Game]"
- local btnWidth = string.len(buttonText)
- local btnX = math.floor((cw - btnWidth) / 2) + 1
- local btnY = ch -- bottom line of inner area
- inner.setCursorPos(btnX, btnY)
- inner.setTextColor(colors.white)
- inner.write(buttonText)
- inner.redraw()
- -- Calculate absolute position of the button for mouse detection.
- win.closeButton = {
- x = win.x + btnX, -- inner window is at win.x+1, but btnX is relative to inner's start at 1
- y = win.y + btnY, -- similarly for y
- width = btnWidth,
- height = 1
- }
- end
- end
- createWindow(prog.name, x, y, w, h, contentFunction)
- end
- --------------------------------------------------
- -- Main Desktop Loop Setup (with two demo windows)
- --------------------------------------------------
- -- Demo windows (non–program windows)
- createWindow("Window 1", 10, 5, 30, 10, function(inner, win)
- inner.setBackgroundColor(colors.black)
- inner.clear()
- inner.setCursorPos(1, 1)
- inner.setTextColor(colors.white)
- inner.write("This is a demo window.")
- inner.redraw()
- end)
- createWindow("Window 2", 20, 8, 30, 10, function(inner, win)
- inner.setBackgroundColor(colors.black)
- inner.clear()
- inner.setCursorPos(1, 1)
- inner.setTextColor(colors.white)
- inner.write("Another demo window.")
- inner.redraw()
- end)
- --------------------------------------------------
- -- Main Desktop Loop
- --------------------------------------------------
- while not exitRequested do
- drawDesktop()
- for _, win in ipairs(windows) do
- if win.visible then
- drawWindow(win)
- end
- end
- drawTaskbar()
- local event, a, b, c, d = os.pullEvent()
- if event == "mouse_click" then
- local button, mx, my = a, b, c
- local screenW, screenH = term.getSize()
- local handled = false
- -- First, check if the click hits any inner [Close Game] button (if defined).
- for i = #windows, 1, -1 do
- local win = windows[i]
- if win.visible and win.closeButton then
- local cb = win.closeButton
- if mx >= cb.x and mx < cb.x + cb.width and my >= cb.y and my < cb.y + cb.height then
- win.visible = false
- handled = true
- break
- end
- end
- end
- if handled then goto continue_mouse_click end
- -- Check if the click is on the taskbar (bottom row)
- if my == screenH then
- if mx >= 1 and mx <= 11 then
- local selected = showProgramMenu()
- if selected then
- runProgram(selected)
- end
- end
- else
- -- Check windows in reverse order (topmost first)
- for i = #windows, 1, -1 do
- local win = windows[i]
- if win.visible and isInWindow(win, mx, my) then
- bringToFront(i)
- if isInResizeHandle(win, mx, my) then
- resizingWindow = win
- break
- elseif isInCloseButton(win, mx, my) then
- win.visible = false
- break
- elseif isInTitleBar(win, mx, my) then
- draggingWindow = win
- dragOffsetX = mx - win.x
- dragOffsetY = my - win.y
- break
- end
- break
- end
- end
- end
- ::continue_mouse_click::
- elseif event == "mouse_drag" then
- local button, mx, my = a, b, c
- if draggingWindow then
- draggingWindow.x = math.max(1, math.min(mx - dragOffsetX, screenW - draggingWindow.w + 1))
- draggingWindow.y = math.max(1, math.min(my - dragOffsetY, screenH - draggingWindow.h))
- elseif resizingWindow then
- local newW = math.max(minWidth, mx - resizingWindow.x + 1)
- local newH = math.max(minHeight, my - resizingWindow.y + 1)
- resizingWindow.w = newW
- resizingWindow.h = newH
- end
- elseif event == "mouse_up" then
- draggingWindow = nil
- resizingWindow = nil
- elseif event == "key" then
- -- If any window is waiting for a key to close (e.g. About), close it.
- for i = #windows, 1, -1 do
- local win = windows[i]
- if win.visible and win.waitForKey then
- win.visible = false
- win.waitForKey = false
- break
- end
- end
- end
- end
- -- Exit: Reset the terminal
- term.setBackgroundColor(colors.black)
- term.clear()
- term.setCursorPos(1,1)
Advertisement
Add Comment
Please, Sign In to add comment