fawhxldawg
Member
Hey,
I'm working on a modular/all-purpose GUI/UI/UX that I'd use from menus, consoles, inventory, settings, prompts etc.
Containing things from arrays of strings(Input and output), numbers, GUI elements like buttons, toggles, sliders, etc.
Basicaqlly just my own GUI suite to meet all my demands in my games.
But as you'd guess, adding all these features into one object starts to make a big object.
(Big for me at least).
And I'm just wondering how would I go about, or how others would or do organize their code?
Because It is starting to feel overwhelming for me despite being easy (for me) to navigate.
I just wonder if being overwhelmed is a normal feeling when you start really fleshing out something like this?
Here is my draw/logic script for my GUI system.
(It iterates through a list of maps; each map being a unique GUI instance)
Note: Maybe skip looking at the code, unless youre really good at figuring out what vague and abridged variablenames mean lol. I guess the syntax wont highlight my enums or macros.
Thanks for any help in advance, I know it is a long script!
Also: Please don't tell me I need to rewrite everything from scratch because I didn't use a certain function that saves 2 bits worth of resources and that my for loops suck, I find criticism like that offensive.
I'm not doing everything the most efficient way certainly but it makes sense to me and I'm comfortable with it and I learn new tricks at my own pace.
I'm just trying to find how people go about making things "feel less big" or easier to navigate.
Or maybe how people break code up into smaller more digestable pieces?
I'm working on a modular/all-purpose GUI/UI/UX that I'd use from menus, consoles, inventory, settings, prompts etc.
Containing things from arrays of strings(Input and output), numbers, GUI elements like buttons, toggles, sliders, etc.
Basicaqlly just my own GUI suite to meet all my demands in my games.
But as you'd guess, adding all these features into one object starts to make a big object.
(Big for me at least).
And I'm just wondering how would I go about, or how others would or do organize their code?
Because It is starting to feel overwhelming for me despite being easy (for me) to navigate.
I just wonder if being overwhelmed is a normal feeling when you start really fleshing out something like this?
Here is my draw/logic script for my GUI system.
(It iterates through a list of maps; each map being a unique GUI instance)
Note: Maybe skip looking at the code, unless youre really good at figuring out what vague and abridged variablenames mean lol. I guess the syntax wont highlight my enums or macros.
GML:
#region Macros, Structs, Enums oh my!
// Ultra Basic
#macro nn noone
#macro t true
#macro f false
#region Window
// Window Basics
// W/H
#macro ww global.window_width
ww = 1024
#macro wh global.window_height
wh = 768
// BG/FG
#macro wbga global.window_background_alpha
wbga = 1
#macro wbgc global.window_background_color
wbgc = c_black
#macro wfga global.window_foreground_alpha
wfga = 1
#macro wfgc global.window_foreground_color
wfgc = c_white
#region Timer/Trigger
// Window Iterators
// Frame
#macro wf global.window_frame
wf = 0
// Second
#macro ws global.window_second
ws = 0
// Minute
#macro wm global.window_minute
wm = 0
#endregion
#region Debug
#macro dbg global.debug
dbg = true
#endregion
#endregion
#region Mouse
// X/Y + Olds
#macro mx mouse_x
#macro my mouse_y
#macro mxo global.mouse_x_old
mxo = mx
#macro myo global.mouse_y_old
myo = my
#macro mxd global.mouse_x_delta
mxd = mx-mxo
#macro myd global.mouse_y_delta
myd = my-myo
// Left
#macro mbl mouse_check_button(mb_left)
#macro mblp mouse_check_button_pressed(mb_left)
#macro mblr mouse_check_button_released(mb_left)
// Right
#macro mbr mouse_check_button(mb_right)
#macro mbrp mouse_check_button_pressed(mb_right)
#macro mbrr mouse_check_button_released(mb_right)
// Wheels
#macro mwu mouse_wheel_up()
#macro mwd mouse_wheel_down()
#endregion
#region Keyboard
#macro kbSHFT keyboard_check(vk_shift)
#macro kbCTL keyboard_check(vk_control)
#endregion
#region Keys
enum k {
xx,
yy,
xy,
w,
h,
bgc,
fgc,
bga,
fga,
bg,
outline,
uid,
active,
scroll,
dialogue,
prompt,
drag,
hilite,
focus,
resize,
label,
l_str, // label string
lc, // label coordinates
l_min_w, // label min width (for minimizing frame)
lga,
lgc,
minimized,
wo,
ho,
str_out,
str_in,
inc, // input coordinates
in_time, // Timestamps?
in_arr, // Input history array
in_arri,
str_arr,
con_xx,
con_yy,
con_ha, // content horiz align
con_va, // content verti align
con_sep,
con_w,
con_offx,
con_offy,
pin,
xbtn,
pbtn,
mbtn
}
#endregion
#endregion
#region Structs
// Margins/Seperators
sep = {
// Basic
sm:5,
md:10,
bg:20,
// Window
ww2:round(ww/2),
ww4:round(ww/4),
ww8:round(ww/8),
ww16:round(ww/16),
wh2:round(wh/2),
wh4:round(wh/4),
wh8:round(wh/8),
wh16:round(wh/16),
// Text
txt:20
}
#endregion
#endregion
draw_gui_frames(){
// 'gfml' being the list of maps holding the data for our gui instances
for(var i = 0; i < ds_list_size(gfml); i++) {
var e = gfml[|i]
// Skip if frame Disabled
if(!e[?k.active]) continue
// Init
var w2 = e[?k.w]/2
var h2 = e[?k.h]/2
#region BG; Drawn first so it is on bottom
if(e[?k.bg]) { // Draw unless bg disabled
if(gfi_focus == i or !e[?k.focus]) draw_set_alpha(e[?k.bga])
else draw_set_alpha(e[?k.bga]/2)
draw_set_color(e[?k.bgc])
draw_rectangle(e[?k.xy][0],e[?k.xy][1],e[?k.xy][2],e[?k.xy][3],f)
}
#endregion
#region Mouse inside frame?
if(mx > e[?k.xy][0] and mx < e[?k.xy][2]
and my > e[?k.xy][1] and my < e[?k.xy][3]) {
// Focus Set
if(e[?k.focus] and (mblr or mblp)) {
gfi_focus = i
}
#region Focused
if(gfi_focus == i or !e[?k.focus]) {
#region Drag and Resize
if(mbl and !e[?k.pin]) {
if(e[?k.resize] and !e[?k.minimized] and kbCTL) {
var wo = e[?k.w]
var ho = e[?k.h]
// Ensure min frame width/height; if label, width is min label size + btns
// Otherwise min is just 1/8th window size
if(e[?k.label]) e[?k.w] = clamp(e[?k.w]+mxd,e[?k.l_min_w],ww)
else e[?k.w] = clamp(e[?k.w]+mxd,sep.ww8,ww)
e[?k.h] = clamp(e[?k.h]+myd,sep.wh8,wh)
if(e[?k.w] != wo) e[?k.xx] += mxd/2
if(e[?k.h] != ho) e[?k.yy] += myd/2
e[?k.wo] = wo
e[?k.ho] = ho
e[?k.con_w] = e[?k.w]-(sep.sm*2)
} else if(e[?k.drag]) {
// Add mouse X/Y Deltas to frame X/Y
e[?k.xx] += mxd
e[?k.yy] += myd
}
}
#endregion
#region Scroll
if(mwu) {
// Scroll wheel up; +Shift for faster
if(kbSHFT) e[?k.con_offy] -= 24
else e[?k.con_offy] -= 12
} else if(mwd) {
// Scroll wheel down; +Shift for faster
if(kbSHFT) e[?k.con_offy] += 24
else e[?k.con_offy] += 12
}
#endregion
}
#endregion
#region Unfocused
/* Not in use
if(gfi_focus != i) {
}
*/
#endregion
} else if(gfi_focus == i and mblr) gfi_focus = nn // Reset focus if clicked off
#endregion
#region Additional Inits
// Update Label Coordinates; Also used by content for adjustments
e[?k.lc][0] = e[?k.xy][0]
e[?k.lc][1] = e[?k.xy][1]
e[?k.lc][2] = e[?k.xy][2]
e[?k.lc][3] = e[?k.xy][3]+(sep.txt*1.5)
// Update Input Coordinates;
// Content Updates; Ensure content stays with frame
e[?k.con_xx] = (e[?k.xy][0])+sep.sm
e[?k.con_yy] = (e[?k.xy][1])+sep.sm
#endregion
#region Content
// String Output;; Skip if minimized so offset y isn't changed
if(e[?k.str_out] and !e[?k.minimized]) {
if(gfi_focus == i or !e[?k.focus]) draw_set_alpha(e[?k.fga])
else draw_set_alpha(e[?k.fga]/2)
draw_set_color(e[?k.fgc])
draw_set_halign(e[?k.con_ha])
draw_set_valign(e[?k.con_va])
var str_h = 0 // hold's total string height drew so far
var arri_h1 = 0 // to hold the first string's height
for(var arri = 0; arri < array_length_1d(e[?k.str_arr]); arri++) {
// get height of current string
var arri_h = string_height_ext(e[?k.str_arr][arri],e[?k.con_sep],e[?k.con_w])
if(arri = 0) arri_h1 = arri_h // Save the height of first string in array for use later in clamping yoffset
// Draw a string from the array while it would still be inside the frame.
if(e[?k.con_yy]+e[?k.con_offy]+str_h > (e[?k.xy][1])
and e[?k.con_yy]+e[?k.con_offy]+str_h+arri_h < (e[?k.xy][3]))
draw_text_ext(e[?k.con_xx]+e[?k.con_offx],(e[?k.con_yy]+e[?k.con_offy])+str_h,
e[?k.str_arr][arri],e[?k.con_sep],e[?k.con_w])
// Add last string height to the total height
str_h += arri_h
// Scroll Clamping; using the strings total height, frame height, first and last string heights...
// We can keep the beginning of the text and end of the text with in the frame while scrolling
if(arri == array_length_1d(e[?k.str_arr])-1 and e[?k.scroll])
e[?k.con_offy] = clamp(e[?k.con_offy],-(str_h-(arri_h+sep.bg)),e[?k.h]-(arri_h1+sep.bg))
}
}
// String input
#endregion
#region Label; Drawn last so it always on top
if(e[?k.label]) {
// Init Button coordinates
// Exit Button
var xbtn
xbtn[0] = e[?k.lc][2]-sep.sm // Coordinates are backwards since button is right-aligned
xbtn[1] = e[?k.lc][3]-sep.sm // i.e. Drawing Bottom-Right to Top-Left
xbtn[2] = xbtn[0]-sep.txt
xbtn[3] = e[?k.lc][1]+sep.sm
var xbtnx = xbtn[2]+((xbtn[0]-xbtn[2])/2)
var xbtny = xbtn[3]+((xbtn[1]-xbtn[3])/2)
// Pin Button
var pbtn
pbtn[0] = xbtn[2]-sep.sm // Coordinates are backwards since button is right-aligned
pbtn[1] = xbtn[1] // i.e. Drawing Bottom-Right to Top-Left
pbtn[2] = pbtn[0]-sep.txt
pbtn[3] = xbtn[3]
var pbtnx = pbtn[2]+((pbtn[0]-pbtn[2])/2)
var pbtny = pbtn[3]+((pbtn[1]-pbtn[3])/2)
// Minimize Button
var mbtn
mbtn[0] = pbtn[2]-sep.sm // Coordinates are backwards since button is right-aligned
mbtn[1] = pbtn[1] // i.e. Drawing Bottom-Right to Top-Left
mbtn[2] = mbtn[0]-sep.txt
mbtn[3] = pbtn[3]
var mbtnx = mbtn[2]+((mbtn[0]-mbtn[2])/2)
var mbtny = (mbtn[3]+((mbtn[1]-mbtn[3])/2))-sep.sm
var btns_w = (xbtn[0]-mbtn[2])+(sep.sm*2) // Get total of buttons width to add to l_min_w
e[?k.l_min_w] = string_width(e[?k.l_str])+btns_w+sep.sm // Update l_min_w
// BG
draw_set_alpha(e[?k.lga])
draw_set_color(e[?k.lgc])
draw_rectangle(e[?k.lc][0],e[?k.lc][1],e[?k.lc][2],e[?k.lc][3],f)
// FG
if(gfi_focus == i or !e[?k.focus]) draw_set_alpha(e[?k.lga])
else draw_set_alpha(e[?k.lga]/2)
draw_set_color(e[?k.fgc])
draw_line(e[?k.lc][0],e[?k.lc][3],e[?k.lc][2],e[?k.lc][3])
// Label
var l_str_x = e[?k.lc][0]+sep.sm
var l_str_y = e[?k.lc][1]+((e[?k.lc][3]-e[?k.lc][1])/2)
draw_set_halign(fa_left)
draw_set_valign(fa_center)
if(gfi_focus == i or !e[?k.focus]) draw_set_alpha(e[?k.lga])
else draw_set_alpha(e[?k.lga]/2)
draw_set_color(e[?k.fgc])
draw_text(l_str_x,l_str_y,e[?k.l_str])
#region Label Buttons
#region X Button
if(mx > xbtn[2] and mx < xbtn[0]
and my > xbtn[3] and my < xbtn[1]
and (gfi_focus == i or !e[?k.focus])) {
if(mbl) draw_set_alpha(e[?k.fga]*.5)
else draw_set_alpha(e[?k.fga]*.75)
draw_set_color(e[?k.fgc])
draw_rectangle(xbtn[0],xbtn[1],xbtn[2],xbtn[3],f)
if(mblr) e[?k.active] = f
} else {
if(gfi_focus == i or !e[?k.focus]) draw_set_alpha(e[?k.fga])
else draw_set_alpha(e[?k.fga]/2)
draw_set_color(e[?k.fgc])
draw_rectangle(xbtn[0],xbtn[1],xbtn[2],xbtn[3],f)
}
if(gfi_focus == i or !e[?k.focus]) draw_set_alpha(e[?k.fga])
else draw_set_alpha(e[?k.fga]/2)
draw_set_color(e[?k.bgc])
draw_set_halign(fa_middle)
draw_set_valign(fa_center)
draw_text(xbtnx,xbtny,"x")
#endregion
#region Pin Button
if(mx > pbtn[2] and mx < pbtn[0]
and my > pbtn[3] and my < pbtn[1]
and (gfi_focus == i or !e[?k.focus])) {
if(mbl) draw_set_alpha(e[?k.fga]*.5)
else draw_set_alpha(e[?k.fga]*.75)
draw_set_color(e[?k.fgc])
if(e[?k.pin]) draw_rectangle(pbtn[0],pbtn[1],pbtn[2],pbtn[3],f)
else draw_rectangle(pbtn[0],pbtn[1],pbtn[2],pbtn[3],t)
if(mblr) e[?k.pin] = !e[?k.pin]
} else {
if(gfi_focus == i) draw_set_alpha(e[?k.fga])
else draw_set_alpha(e[?k.fga]/2)
draw_set_color(e[?k.fgc])
if(e[?k.pin]) draw_rectangle(pbtn[0],pbtn[1],pbtn[2],pbtn[3],f)
else draw_rectangle(pbtn[0],pbtn[1],pbtn[2],pbtn[3],t)
}
#endregion
#region Min Button
if(mx > mbtn[2] and mx < mbtn[0]
and my > mbtn[3] and my < mbtn[1]
and gfi_focus == i) {
if(mbl) draw_set_alpha(e[?k.fga]*.5)
else draw_set_alpha(e[?k.fga]*.75)
draw_set_color(e[?k.fgc])
draw_rectangle(mbtn[0],mbtn[1],mbtn[2],mbtn[3],f)
if(mblr) frame_minimize(e)
} else {
if(gfi_focus == i) draw_set_alpha(e[?k.fga])
else draw_set_alpha(e[?k.fga]/2)
draw_set_color(e[?k.fgc])
draw_rectangle(mbtn[0],mbtn[1],mbtn[2],mbtn[3],f)
}
if(gfi_focus == i) draw_set_alpha(e[?k.fga])
else draw_set_alpha(e[?k.fga]/2)
draw_set_color(e[?k.bgc])
draw_set_halign(fa_middle)
draw_set_valign(fa_center)
draw_text(mbtnx,mbtny,"_")
#endregion
#endregion
}
#endregion
#region Stretch Indicator
if((gfi_focus == i or !e[?k.focus]) and kbCTL and !e[?k.pin] and e[?k.resize]) {
// Init Triangle X/Y; Bottom Right Corner
var xx1 = (e[?k.xy][2])-sep.sm
var yy1 = (e[?k.xy][3])-sep.sm
var xx2 = xx1-sep.bg
var yy2 = yy1
var xx3 = xx1
var yy3 = yy1-sep.bg
draw_set_alpha(e[?k.fga])
draw_set_color(e[?k.fgc])
draw_triangle(xx1,yy1,xx2,yy2,xx3,yy3,f)
}
#endregion
#region FG; Drawn Last so it is on top
if(e[?k.outline]) { // Draw unless outline disabled
if(gfi_focus == i or !e[?k.focus]) draw_set_alpha(e[?k.fga])
else draw_set_alpha(e[?k.fga]/2)
draw_set_color(e[?k.fgc])
draw_rectangle(e[?k.xy][0],e[?k.xy][1],e[?k.xy][2],e[?k.xy][3],t)
}
#endregion
#region General Frame Updates
// XY
e[?k.xy][0] = e[?k.xy][0]
e[?k.xy][1] = e[?k.xy][1]
e[?k.xy][2] = e[?k.xy][0]+e[?k.w]
e[?k.xy][3] = e[?k.xy][1]+e[?k.h]
#endregion
}
return nn
}
Also: Please don't tell me I need to rewrite everything from scratch because I didn't use a certain function that saves 2 bits worth of resources and that my for loops suck, I find criticism like that offensive.
I'm not doing everything the most efficient way certainly but it makes sense to me and I'm comfortable with it and I learn new tricks at my own pace.
I'm just trying to find how people go about making things "feel less big" or easier to navigate.
Or maybe how people break code up into smaller more digestable pieces?
Last edited: