Jump to content
  • Sky
  • Blueberry
  • Slate
  • Blackcurrant
  • Watermelon
  • Strawberry
  • Orange
  • Banana
  • Apple
  • Emerald
  • Chocolate
  • Charcoal
Dustpuppy

My gui (Now with visual editor)

Recommended Posts

As an author of a few programs that heavily used different GUI libraries, I have found problems in your current library. The approach it going to work for really simple programs, but when someone uses it for bigger projects, it becomes really hard to use. Below are some of problems I've found. You wanted feedback, after all.

Why not use OOP? So that GUI elements could be modified in some way by calling its method, like menu:addSeparator(). OOP is a really great choice when making GUI libraries.

It's incredibly hard to add a custom element that would use your GUI system. Every program with GUI I've written needed some elements that were not provided by a GUI library I used. With proper OOP, it becomes a really easy thing. Without OOP or support for adding custom objects, it's often a pain.

Your code exports some functions to the global environment. A user can accidentally override such functions and break the library. Use local whenever possible. Only export functions via the return statement. (Note, adding local when defining function in a table is a syntax error: local function tbl.func() end will not work.)

GUIs quickly become more complex as more features are added. Using your library, it's hardly possible to change a button callback to another function. Ideally, it'd be something like button.callback = function() print("Now it does something else") end. You also can't switch a button to the pressed state, you can't add child objects (like a label on a frame in a container).

Share this post


Link to post
Share on other sites

The export of local functions i've solved.

Functions can be changed on every element.

Now a kind of custom element can be set by using the new element  function directly. So, it's possible to make multiline label, taht acts like a button.

 

But i have no clue about OOP. Never used it.

Started coding when i used OC the first time ;-)

 

Share this post


Link to post
Share on other sites

@Fingercomp makes a great point. 

1 hour ago, Fingercomp said:

Why not use OOP? So that GUI elements could be modified in some way by calling its method (...)

Without trying to use too much jargon.. OOP or Object Oriented Programming is a style of program or library organization that pairs 'Classes' with 'Instances'.

This is hard to explain so I'll use an example that hopefully will demonstrate why OOP can be a powerful paradigm and useful to learn.

-- # Person. Our 'Base' class for a set of more complex classes.
local Person = {} -- # Use Person(name, age, sex) to use as an instance constructor.
Person.__index = Person
setmetatable(Person, {
  __call = function(_, name, age, sex)
  	local person = {
      name = name,
      age = age,
      sex = sex
    }
    
    return setmetatable(person, Person)
  end
})

function Person:introduce()
  return ("Hello, my name is %s."):format(self.name)
end

function Person:greet(otherPerson)
  return self:introduce() .. (" Nice to meet you %s."):format(otherPerson.name)
end


-- # Now we can create 'Persons' or 'instances' of Persons as we call them in OOP.
local bob = Person('Bob', 49, 'male')
local jane = Person('Jane', 33, 'female')

print( bob:greet(jane) ) -- # > "Hello, my name is Bob. Nice to meet you Jane."

-- # This is where OOP really shines and why it would be recommeneded. 'Inheritance'.
local Wizard = {}
Wizard.__index = Wizard

setmetatable(Wizard, {
  __call = function(_, name, age, sex, spells)
  	local wizard = Person(name, age, sex) -- # create a wizard from the Person class. Wizards are people too. Not all People are Wizards.
    wizard.spells = spells -- # Wizard specific
    
    return setmetatable(wizard, Wizard) -- # bestow Wizard methods upon wizard instance.
  end,
  
  -- # inheritance
  __index = Person -- # If a method or field isn't within a 'Wizard' then fallback to the 'Base' which is 'Person'. i.e wizardInstance:greet(bob)
})

-- # Sub-class method override.
function Wizard:introduce() -- # Wizard introductions should state the prestige that they are Wizards!
  return ("Hello, my name is %s the wizard."):format(self.name)
end

-- # Wizard:greet is inherited from Person. 

function Wizard:cast(spell, target)
  assert(self.spells[spell], "Invalid spell. Your Wizard is weak.")
  return ("%s the wizard casts '%s' upon %s for %d damage."):format(self.name, spell, target.name, self.spells.damage)
end

local merlin = Wizard("Merlin", 61, "male", {
  ["Abbra"] = {
  	name = "Abbra",
    damage = 12
  }
})

-- # Notice :greet() is inherited from Person class but uses the merlin instances version of :introduce()
print( merlin:greet(bob) ) -- # > "Hello, my name is Merlin the wizard. Nice to meet you Bob."
print( merlin:cast('Abbra', bob) ) -- # > "Merlin the wizard casts 'Abbra' upon Bob for 12 damage."

-- # End

I hope this example can illustrate to you the advantages of  OOP design. Any questions? ask away :)

Share this post


Link to post
Share on other sites

OK, now i am fully lost. That's too much for my little brain at the moment. Don't you think it is too complicated for the normal user? Most people using lua in OC are beginners , not coders. Even it is complicated to me, i am talking about the normal player, who just want to put some information on his screen.

 

Share this post


Link to post
Share on other sites

yeah.. I was worried it might just look like spaghetti...

3 hours ago, Dustpuppy said:

Don't you think it is too complicated for the normal user? Most people using lua in OC are beginners , not coders. Even it is complicated to me, i am talking about the normal player, who just want to put some information on his screen.

Yes and No. Yes. The user of the library doesn't need or want to know how the library works to be able to use it and shouldn't have to either. No, because anyone like @Fingercomp who might like to use your library, even if it lacks a specific element, might like to be able to integrate a custom element and not have to write an entire library to do it. A good example would be to think of how similar a 'Label' and a 'Button' object are to each other. They can share ~90% of their code, so why rewrite the other 90% of a button if its just like a label with a touch event listener. 

-- # ... more gui shit above..

local Label = {}
Label.__index = Label

function Label:draw(fg, bg)
  local ofg, obg = gpu.setForground(fg), gpu.setBackground(bg)
  -- # self here refers to the label instance. The specific label calling draw. Label:draw is really a shorcut for Label.draw(labelInstance, fg, bg)
  gpu.fill(self.x, self.y, self.width, self.height, " ") -- # draw the box
  gpu.set( math.floor((self.x + self.width - 1) / 2 + #self.text / 2 + .5), math.floor(self.height / 2 + .5), self.text ) -- # center the label text. ugly
  gpu.setForground(ofg) -- # reset the fg and bg colors
  gpu.setBackground(obg)
end

local function newLabel(x, y, text, w, h)
  return setmetatable({
    x = x,
    y = y,
    text = text,
    width = w,
    height = h
  }, Label)
end

local Button = setmetatable({}, {__index = Label}) -- # look to Label for :draw method
Button.__index = Button

local function newButton(x, y, text, w, h, action)
  local button = newLabel(x, y, text, w, h)
  button.action = action
  
  local listener = function(...)
    local _, x, y = ...
    if x >= self.x and x <= self.x + self.width - 1 then
      if y >= self.y and y <= self.y + self.height - 1 then
        action()
      end
    end
  end
  
  event.listen('touch', listener) -- # this is easy for the demo here but can be a memory leak if left after the program ends...
  
  return setmetatable(button, Button)
end

-- # End

I hope this example, although not much less complicated, will help convey the point.

Share this post


Link to post
Share on other sites

When I was writing that response, I didn't really know, well, how experienced you are at Lua programming. :)

OOP in general, not in Lua, isn't really advanced. Many languages allow to write in object-oriented style. To name a few: Java, Python, C++. If you don't know what OOP is, writing a few programs in these languages can help to understand the subject.

OOP in Lua is really complicated. It requires using of metatables -- and that is advanced. In library, the code may quickly become complicated and hard to maintain. Instead of messing with metatables, I prefer to use libraries that nicely hide all the mess.

It's just me searching for the greatest library possible, and someone would need quite a lot of Lua experience to create a library I would be satisfied with. So if you don't want to rewrite the whole GUI library once again and want to keep it as it is, I am not going to stop you. If you can't do OOP, do what you can, or you can easily lose the motivation. Create the library you want, not I. Your current way is very beginner-friendly, so Lua beginners might use it, while I would stick to using some other library.

Share this post


Link to post
Share on other sites
7 minutes ago, Fingercomp said:

When I was writing that response, I didn't really know, well, how experienced you are at Lua programming. :)

Thanks, you're nice :). It was my first language.

7 minutes ago, Fingercomp said:

OOP in general, not in Lua, isn't really advanced. Many languages allow to write in object-oriented style. To name a few: Java, Python, C++. If you don't know what OOP is, writing a few programs in these languages can help to understand the subject.

^^^ THIS. So much yes. I had a hard time grasping the concept of OOP at first because Lua doesn't have many of the features an OO language like Java and so on.. 

Personally an OOP-like library is the only real practical way in my opinion to even use OO in Lua. Writing actual program logic doesn't work so well this way..  Gets bloated quick. BUT, an OO library is easy to extend for a use case should you need it.

13 minutes ago, Fingercomp said:

It's just me searching for the greatest library possible, and someone would need quite a lot of Lua experience to create a library I would be satisfied with.

Oh boy I've been trying forever to get this right. When I do I'll let you know :P.

@Dustpuppy

15 minutes ago, Fingercomp said:

If you can't do OOP, do what you can, or you can easily lose the motivation. Create the library you want, not I. Your current way is very beginner-friendly, so Lua beginners might use it

I agree. I just wanted to show you how big the world is... lol. If you really want to twist your brain for the better check out Functional programming. Also, a useful mind-fuck. As for the intended style Lua was built for... I believe its intended to be Procedural with a dash of meta-programming. As I said earlier, Lua was my first and still my favorite.

This has been a nice discussion :).

Share this post


Link to post
Share on other sites

Awesome Gui. Im very new to Lua but not to Programming at all. With this Gui i was able to do the stuff i wanted. Terrasteel Automation.

Well my Program isnt finished yet, and needs some advanced stuff to do to like mana checks etc. but it works well for now and at least for me. 

Your Designer has some issues with List Creation it lacks beginning " and ending " in the List Title but its easy to fix it myself. 

I searched so much on youtube and reddit posts for some solutions to create it fully automated, but got only some hints and ideas. so i'll share the WIP Code here 

for someones needs. 

 

The Setup is kinda simple. its just a very Small Refined Storage system wich holds just the Credients needed for the Terrasteel Ingot. 
Then it needs just an Interface + OC Adapter without any Upgrade in it. Then there is 1 Chest wich gets the Items step by step with a 5 seconds sleep timer
to get ready for the next one (this may be adjusted for slower mana flows so the steel can be made till the next items can put in place with the Open Crate.
Another Chest with an Advanced Item Collector (Random Things mod with item filter) takes the Terrasteel only. (I personally take this chest into my AE2 ME System but you can work
with whatever you want here. Hope this helps one or another. Keep in mind its still WIP, working but needs additional checks and things. But you get ideas as well.
Cheers Coco <3

 

local component = require("component")
local gpu = component.gpu
gpu.setResolution(160,50)
local gui = require("gui")
local event = require("event")
local sides = require("sides")
 
local rsInterface = component.block_refinedstorage_interface
 
gui.checkVersion(2,5)
 
local prgName = "botanics"
local version = "v1.0"
 
 
local function getContentAmount(material)
  local allItems = rsInterface.getItems()
 
  for i, item in ipairs(allItems) do
    if(item.label == material) then
      --getContent = rsInterface.getItem(item, true)
      return (item.size)
    end
  end
end
 
local function getItemToCraft(material)
  local allItems = rsInterface.getItems()
 
  for s, item in ipairs(allItems) do
    if(item.label == material) then
      --local getCraftItem = rsInterface.getItem(item, true)
      rsInterface.extractItem(item, 1, sides.right)    
    end
  end
end
 
-- Begin: Callbacks
local function order_list_callback(guiID, listID, selected, text)
   -- Your code here
    if (text == 'Terrasteel') then
      material_label = 'Terrasteel'
      material_content_1 = 'Mana Pearl'
      material_content_2 = 'Manasteel Ingot'
      material_content_3 = 'Mana Diamond'
      material_amount_1 = getContentAmount(material_content_1)
      material_amount_2 = getContentAmount(material_content_2)
      material_amount_3 = getContentAmount(material_content_3)
    else
      material_label = 'Waehle aus'
      material_content_1 = ''
      material_content_2 = ''
      material_content_3 = ''
    end
 
    gui.newLabel(mainGui, 56, 2, ""..material_label.."", 0xc3c3c3, 0x0, 15)
 
    gui.newLabel(mainGui, 56, 4, ""..material_content_1.."", 0xc3c3c3, 0x0, 15)
      if (text == 'Terrasteel' and material_amount_1 > 0) then
        gui.newLabel(mainGui, 75, 4, ""..material_amount_1.."", 0xc3c3c3, 0x33ff00, 7)
      else
        gui.newLabel(mainGui, 75, 4, "missing", 0xc3c3c3, 0xff0000, 7)    
      end
 
    gui.newLabel(mainGui, 56, 5, ""..material_content_2.."", 0xc3c3c3, 0x0, 15)
      if (text == 'Terrasteel' and material_amount_2 > 0) then
        gui.newLabel(mainGui, 75, 5, ""..material_amount_2.."", 0xc3c3c3, 0x33ff00, 7)
      else
        gui.newLabel(mainGui, 75, 5, "missing", 0xc3c3c3, 0xff0000, 7)
      end
 
    gui.newLabel(mainGui, 56, 6, ""..material_content_3.."", 0xc3c3c3, 0x0, 15)
      if (text == 'Terrasteel' and material_amount_3 > 0) then
        gui.newLabel(mainGui, 75, 6, ""..material_amount_3.."", 0xc3c3c3, 0x33ff00, 7)
      else
        gui.newLabel(mainGui, 75, 6, "missing", 0xc3c3c3, 0xff0000, 7)
      end
 
    gui.displayGui(mainGui)
end
 
local function text_menge_callback(guiID, textID, text)
   local toCraft = text
   return toCraft
end
 
local function button_start_callback(guiID, buttonID)
   local toCraft = guiID[3].text
   local counter = 0
   local limiters = tonumber(toCraft)
   progress = gui.newProgress(guiID, 2, 18, 35, limiters, 0, nil, true)
 
 
   for i = 1, toCraft do
--    print(toCraft, material_label, material_content_1, material_content_2, material_content_3)
    gui.displayGui(guiID)
 
    getItemToCraft(material_content_1)
    getItemToCraft(material_content_2)
    getItemToCraft(material_content_3)
   
    order_list_callback(guiID, nil, nil, material_label)
   
    counter = counter + 1
    if counter <= limiters then
      gui.setValue(guiID, progress, counter)
    end
    if counter > limiters then
      counter = 0
    end
    os.sleep(5)
   end
 
end
 
 
local function exitButtonCallback(guiID, id)
   local result = gui.getYesNo("", "Do you really want to exit?", "")
   if result == true then
      gui.exit()
   end
   gui.displayGui(mainGui)
   refresh()
end
-- End: Callbacks
 
-- Begin: Menu definitions
mainGui = gui.newGui(2, 2, 158, 48, true)
order_list = gui.newList(mainGui, 1, 1, 50, 15, {}, order_list_callback, "Was soll hergestellt werden?")
gui.insertList(mainGui, order_list, "Waehle aus")
gui.insertList(mainGui, order_list, "Terrasteel")
label_menge = gui.newLabel(mainGui, 54, 12, "Menge:", 0xc3c3c3, 0x0, 7)
text_menge = gui.newText(mainGui, 54, 13, 10, "0", text_menge_callback, 20, false)
button_start = gui.newButton(mainGui, 54, 15, "Starten", button_start_callback)
frame_info = gui.newFrame(mainGui, 54, 1, 40, 10)
exitButton = gui.newButton(mainGui, 151, 48, "exit", exitButtonCallback)
-- End: Menu definitions
 
gui.clearScreen()
gui.setTop("Terrestrial Agglomeration Plate Automation")
gui.setBottom("Made with Visual Gui v0.1a and Gui library v2.5")
 
-- Main loop
while true do
   gui.runGui(mainGui)
end


 

 

Share this post


Link to post
Share on other sites

Hi, i have a lil problem with the gui, whenever my chunk is unload, the computer shutdown, and when i comeback, i can't make it works again.
Everything made with the lib doesn't work, it show the blue screen of the interface, but doesn't add any button or component, and just makes me return to the /home folder. any help please

Share this post


Link to post
Share on other sites

I have error:image.thumb.png.ca04bac6a968a4a17988efa1820c5289.png

Code is:

local component = require("component")
local gpu = component.gpu
gpu.setResolution(80,25)
local gui = require("gui")
local event = require("event")

gui.checkVersion(2,5)

local prgName = "security"
local version = "v1.0"

-- Begin: Callbacks
local function fire(guiID, buttonID)
   -- Your code here
end

local function armoured-true(guiID, buttonID)
   -- Your code here
end

local function armoured-false(guiID, buttonID)
   -- Your code here
end

local function power-on(guiID, buttonID)
   -- Your code here
end

local function power-off(guiID, buttonID)
   -- Your code here
end

local function height(guiID, textID, text)
   -- Your code here
end

local function rotation(guiID, textID, text)
   -- Your code here
end

local function exitButtonCallback(guiID, id)
   local result = gui.getYesNo("", "Do you really want to exit?", "")
   if result == true then
      gui.exit()
   end
   gui.displayGui(mainGui)
   refresh()
end
-- End: Callbacks

-- Begin: Menu definitions
mainGui = gui.newGui(1, 2, 79, 23, true)
Fire = gui.newButton(mainGui, 1, 1, "Fire!", fire)
Rotaion-label = gui.newLabel(mainGui, 1, 3, "Rotation", 0xc0c0c0, 0x0, 7)
Height-label = gui.newLabel(mainGui, 1, 5, "Height", 0xc0c0c0, 0x0, 7)
Armoured-true = gui.newButton(mainGui, 27, 1, "Set ready", armoured-true)
Armoured-false = gui.newButton(mainGui, 12, 1, "Not ready", armoured-false)
Power-on = gui.newButton(mainGui, 42, 1, "Power on", power-on)
Power-off = gui.newButton(mainGui, 56, 1, "Power off", power-off)
Height-value = gui.newText(mainGui, 10, 5, 2, "", height, 10, false)
Rotation-value = gui.newText(mainGui, 10, 3, 2, "", rotation, 10, false)
exitButton = gui.newButton(mainGui, 73, 23, "exit", exitButtonCallback)
-- End: Menu definitions

gui.clearScreen()
gui.setTop("Energy turret operation software")
gui.setBottom("Made with Visual Gui v0.1a and Gui library v2.5")

-- Main loop
while true do
   gui.runGui(mainGui)
end

 

Share this post


Link to post
Share on other sites

i don't know if its the guis fault but back space throws a symbol instead of working on 2 programs that clearly uses your gui editor btw I run micraft on a Mac OS X system

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use and Privacy Policy.