Can anyone show a way to make dynamic UI elements in maxscript?
For example. I can insert a image button in the ui, but i'd like to control the scale of the image based on the value of a slider element.
I did find a way to make a dynamic user interface,
that was the first part of the problem.
But i did not get it to make image button sizes dynamic yet.(mainly because if i use group elements in the way i want to, then the position of every element is hard coded.
try(destroydialog dRolH) catch()
rollout dRolH "Dialog" height:200 width:200
(
dropdownlist rolList "Rollouts: " items:#("Rollout A", "Rollout B", "Rollout C") width:175 offset:[0,0]
checkbox lbA "A" pos:[14,50] visible:off
checkbox lbB "B" pos:[14,50] visible:off
checkbox lbC "C" pos:[14,50] visible:off
local rolls = #(#(lbA), #(lbB), #(lbC))
on rolList selected sel do
(
for k=1 to rolls.count do for c in rolls[k] do c.visible = (k == sel)
)
)
createDialog dRolH pos:[740, 200]
See, this is a bit more complicated.
Changing the width and height values of the bitmap element is pretty easy:
bitmap bm "Bitmap:" filename:#"some/file/path.jpg" -- create the bitmap UI element
bm.width = 100
bm.height = 100
But this will only change the size of the bitmap framing. You will also need to rerender the bitmap in a new resolution and switch out the old one. I have implemented this in your code here:
try(destroydialog dRolH) catch()
rollout dRolH "Dialog" height:200 width:200
(
dropdownlist rolList "Rollouts: " items:#("Rollout A", "Rollout B", "Rollout C") width:175 offset:[0,0]
checkbox lbA "A" pos:[14,50] visible:off
checkbox lbB "B" pos:[14,50] visible:off
checkbox lbC "C" pos:[14,50] visible:off
spinner s "Size (%)" range:[0,1000,100]
local bm_height = 128
local bm_width = 128
bitmap bm "Bitmap" height:bm_height width:bm_width fileName:#"C:\ProgramData\Microsoft\User Account Pictures\Default Pictures\usertile12.bmp"
fn scaleAndReloadImage factor =
(
-- New sizes
bm.height = bm_height * factor
bm.width = bm_width * factor
-- Loadimage and
local image = Bitmaptexture filename:#"C:\ProgramData\Microsoft\User Account Pictures\Default Pictures\usertile12.bmp"
-- Rerender into new bitmap
local new_bm = bitmap bm.width bm.height
rendermap image into:new_bm size:([image.bitmap.width,image.bitmap.height]) filter:on display:off gamma:2.2
-- Assign new bitmap
bm.bitmap = new_bm
)
-- EVENTS
local rolls = #(#(lbA), #(lbB), #(lbC))
on rolList selected sel do
(
for k=1 to rolls.count do for c in rolls[k] do c.visible = (k == sel)
)
on s changed val do
(
if val == 0 then s.value = val = 100 -- Resets to 100 on rightclick
local factor = val / 100 -- Scaling factor
scaleAndReloadImage factor
)
on dRolH open do
(
scaleAndReloadImage 1 -- Render image from start, to secure uniform gamma
)
)
createDialog dRolH pos:[740, 200] height:400
I have put in a few comments for you as well.
Happy hacking :D :)
/goehler
NB: The address I use for the bitmap will probably only work in Windows 7 - but I imagine you have the sense to use another address if need be :)
Related
i'm trying to make a Nurikabe puzzle with Ruby GTK and i'm having trouble creating button signals dynamically.
Basically, i have a matrix, some boxes have a number ( clicking them won't do anything), others can have one of 3 states (white, black or unplayed). The matrix can have different sizes so i did this :
def construction
# we get the width and height of the matrix
taille_hauteur = ##partie.grilleEnCours.hauteur
taille_largeur = ##partie.grilleEnCours.largeur
#boutons = {}
#We create a table which will include all of our buttons (one for each box of our matrix)
table = Table.new(taille_hauteur,taille_largeur,false)
# we go through our matrix
for i in 0..taille_largeur-1
for j in 0..taille_hauteur-1
# if the box has a number, we create a button with that number as a label
if ##partie.grilleEnCours.matriceCases[i][j].is_a?(CaseNombre)
# we add this button to a hash
#boutons[[i,j]] = Button.new(:label=> ##partie.grilleEnCours.matriceCases[i][j].to_s)
table.attach(#boutons[[i,j]], i, i+1, j, j+1)
else
# otherwise,we create and add a button to the hash without a label
#boutons[[i,j]] = Button.new()
# we create a signal, changing the state of the box of the matrix at the same coordinates as the button
#boutons[[i,j]].signal_connect('clicked'){
puts "#{i} #{j}"
# we change the box's state of the matrix
##partie.clicSurCase(i,j)
puts ##partie.grilleEnCours
# here we are just changing the label corresponding to the box's state
if(##partie.grilleEnCours.matriceCases[i][j].etat==0)
lab = ""
elsif (##partie.grilleEnCours.matriceCases[i][j].etat==1)
lab = "Noir"
else
lab = "Point"
end
#boutons[[i,j]].set_label(lab)
}
table.attach(#boutons[[i,j]], i, i+1, j, j+1)
end
end
end
#object.add(table)
end
The problem is, doing this, when we click any button, it will change the last box of the matrix and the last button's label (bottom right). I believe this is because Integers are objects in Ruby so clicking a button will change the box's state and button's state at the coordinates (i,j) (which are matrix height-1, matrix width-1) and not the values i and j had when we created the signal.
I have no idea how to link a button to a specific box of the matrix (knowing matrixes can have multiple sizes), could you help me on this one ?
It is quite hard to read such a large block of code - maybe start by chopping it into logic-based functions?
It will clear the code up.
you don't need to set "lab =" in each branch of if - just:
lab = if (i==1)
1
else
2
end
in additions - use "case" in this case. Once you split the code up - you will(probably) find the issue you have.
it will be easier to debbug.
I made a code using pysimplegui. it basically shows some images from a database based on a scanned number. it works but sometimes it could be useful to be able to increase the size of the image + it would make my user interface a bit more interactive
i want to have the possibility to either:
when i fly over the image with the mouse, i want the image to increase in size
have the possibility to clic on the image and have a pop-up of the image showing up (in a bigger size)
i am not sure on how to interact with a sg.image()
Below you will find a trunkated part of my code where i show my way of getting the image to show up.
layout = [
[
sg.Text("Numéro de boîte"),
sg.Input(size=(25, 1), key="-FILE-"),
sg.Button("Load Image"),
sg.Button("Update DATA"),
sg.Text("<- useless text ")
],
[sg.Text("Indicateur au max" , size = (120, 1),font = ("Arial", 18), justification = "center")],
[sg.Image(key="-ALV1-"),sg.Image(key="-ALV2-"), sg.Image(key="-ALV3-"), sg.Image(key="-ALV4-"), sg.Image(key="-ALV5-")],
[sg.Image(key="-ALV6-"),sg.Image(key="-ALV7-"), sg.Image(key="-ALV8-"), sg.Image(key="-ALV9-"), sg.Image(key="-ALV10-")],
[sg.Text("_" * 350, size = (120, 1), justification = "center")],
[sg.Text("Indicateur au milieu" , size = (120, 1),font = ("Arial", 18), justification = "center")],
[sg.Image(key="-ALV11-"),sg.Image(key="-ALV12-"), sg.Image(key="-ALV13-"), sg.Image(key="-ALV14-"), sg.Image(key="-ALV15-")],
[sg.Image(key="-ALV16-"),sg.Image(key="-ALV17-"), sg.Image(key="-ALV18-"), sg.Image(key="-ALV19-"), sg.Image(key="-ALV20-")],
[sg.Text("↓↓↓ ↓↓↓" , size = (120, 1),font = ("Arial", 18), justification = "center")],
]
ImageAlv1 = Image.open(PathAlv1)
ImageAlv1.thumbnail((250, 250))
bio1 = io.BytesIO()
ImageAlv1.save(bio1, format="PNG")
window["-ALV1-"].update(data=bio1.getvalue())
Using bind method for events, like
"<Enter>", the user moved the mouse pointer into a visible part of an element.
"<Double-1>", specifies two click events happening close together in time.
Using PIL.Image to resize image and io.BytesIO as buffer.
import base64
from io import BytesIO
from PIL import Image
import PySimpleGUI as sg
def resize(image, size=(256, 256)):
imgdata = base64.b64decode(image)
im = Image.open(BytesIO(imgdata))
width, height = size
w, h = im.size
scale = min(width/w, height/h)
new_size = (int(w*scale+0.5), int(h*scale+0.5))
new_im = im.resize(new_size, resample=Image.LANCZOS)
buffer = BytesIO()
new_im.save(buffer, format="PNG")
return buffer.getvalue()
sg.theme('DarkBlue3')
number = 4
column_layout, line = [], []
limit = len(sg.EMOJI_BASE64_HAPPY_LIST) - 1
for i, image in enumerate(sg.EMOJI_BASE64_HAPPY_LIST):
line.append(sg.Image(data=image, size=(64, 64), pad=(1, 1), background_color='#10C000', expand_y=True, key=f'IMAGE {i}'))
if i % number == number-1 or i == limit:
column_layout.append(line)
line = []
layout = [
[sg.Image(size=(256, 256), pad=(0, 0), expand_x=True, background_color='green', key='-IMAGE-'),
sg.Column(column_layout, expand_y=True, pad=(0, 0))],
]
window = sg.Window("Title", layout, margins=(0, 0), finalize=True)
for i in range(limit+1):
window[f'IMAGE {i}'].bind("<Enter>", "") # Binding for Mouse enter sg.Image
#window[f'IMAGE {i}'].bind("<Double-1>", "") # Binding for Mouse double click on sg.Image
element = window['-IMAGE-']
now = None
while True:
event, values = window.read()
if event == sg.WINDOW_CLOSED:
break
elif event.startswith("IMAGE"):
index = int(event.split()[-1])
if index != now:
element.update(data=resize(sg.EMOJI_BASE64_HAPPY_LIST[index]))
now = index
window.close()
I'm trying to create a maxscript which offsets selected keyframes in the curve editor by specified amount to aid in some animation however I have zero experience in scripting in max. I tried searching on scriptspot for relevant tools but none seems to fit my need and script listener is not helping.
Currently, I only have the UI done
rollout MoveKeyTool "Move Key"
(
group "Settings"
(
spinner OffsetBySpn "Offset by" type:#integer
button OffsetFramesBt "Offset Keyframes"
on OffsetFramesBt pressed do
(
)
)
)
createdialog MoveKeyTool
Any help or advice is greatly appreciated, thank you.
try destroyDialog ::MoveKeyTool catch()
rollout MoveKeyTool "Move Key"
(
group "Settings"
(
spinner OffsetBySpn "Offset by" type:#integer range:[-1e3,1e3,10]
button OffsetFramesBt "Offset Keyframes"
on OffsetFramesBt pressed do
(
local currentTV = trackViews.current
if currentTV == undefined do return messageBox "Trackview window has to be open."
local selCount = currentTV.numSelTracks()
for i = 1 to selCount
where (local ctrl = currentTV.getSelected i).keyable do
moveKeys ctrl OffsetBySpn.value #selection
)
)
)
createdialog MoveKeyTool
I have 3 images and 1 button -
I want to be able to click my button and have 1 of the 3 images appear. And everytime I click the button i want a new random image to appear in the place of the last image......Pretty simple it would seem, but Im losing hair over this and am about to call it quits......Can anyone help me do this? I want to learn, so please comment the code if you decide to help me....Thanks in advance.
So far, I have:
display.setStatusBar( display.HiddenStatusBar ) -- hide status bar
--insert background
local bgImg = display.newImageRect( "images/myBG.jpg", 625, 450 )
bgImg.x = display.contentCenterX -- center bg on X
bgImg.y = display.contentCenterY -- center bg on Y
-- scripture references
myTable = {
display.newImage("images/btnLogo1.png"),
display.newImage("images/btnLogo2.png"),
display.newImage("images/btnLogo3.png"),
}
randomPicture = myTable[math.random(1,3)]
This should work:
-- scripture references
myTable = {
"images/btnLogo1.png",
"images/btnLogo2.png",
"images/btnLogo3.png",
}
local randomPicture = myTable[math.random(1,3)]
display.newImage(myTable[randomPicture])
I hope you need no explanation about it :)
If your image names are continous, that is like img_1,img_2,img_3. etc... then you can use the following method:
-- Display an image
local myImage = display.newImageRect("images/btnLogo1.png",50,50)
myImage.x = display.contentWidth/2
myImage.y = display.contentHeight/2
-- Call this function on button click
function imageChangeFunction()
-- remove the previous image
if(myImage)then myImage:removeSelf() end
-- creating the sprite with new image
myImage = display.newImageRect("images/btnLogo"..math.random(3)..".png",50,50)
myImage.x = display.contentWidth/2
myImage.y = display.contentHeight/2
print("Image changed...")
end
-- Here I am assigning the listener to Runtime, you can change it for your button
Runtime:addEventListener("tap",imageChangeFunction)
Note:
math.random(3) gives you any random number between 1 and 3.
.. is used for concatenation. So, "images/btnLogo"..math.random(3)..".png" will give you any of the following strings:
images/btnLogo1.png
images/btnLogo2.png
images/btnLogo3.png
For more info, visit: math.random() and Corona String Operations
I would like to create an animation which enables the user to go backward and forward through the steps of simulation.
An animation has to simulate the iterative process of channel decoding (a receiver receives a block of bits, performs an operation and then checks if the block corresponds to parity rules. If the block doesn't correspond the operation is performed again and the process finally ends when the code corresponds to a given rules).
I have written the functions which perform the decoding process and return a m x n x i matrix where m x n is the block of data and i is the iteration index. So if it takes 3 iterations to decode the data the function returns a m x n x 3 matrix with each step is stired.
In the GUI (.fig file) I put a "decode" button which runs the method for decoding and there are buttons "back" and "forward" which have to enable the user to switch between the data of recorded steps.
I have stored the "decodedData" matrix and currentStep value as a global variable so by clicking "forward" and "next" buttons the indices have to change and point to appropriate step states.
When I tried to debug the application the method returned the decoded data but when I tried to click "back" and "next" the decoded data appeared not to be declared.
Does anyone know how is it possible to access (or store) the results of the functions in order to enable the described logic which I want to implement in Matlab GUI?
Ultimately, this is a scoping of variables problem.
Global variables is rarely the right answer.
This video discusses the handles structure in GUIDE:
http://blogs.mathworks.com/videos/2008/04/17/advanced-matlab-handles-and-other-inputs-to-guide-callbacks/
This video discusses sharing of variables between GUIs and could apply to a single GUI problem also.
http://blogs.mathworks.com/videos/2005/10/03/guide-video-part-two/
The trick is to use nested functions so that they share the same workspace. Since I already started with an example in your last question, now I'm simply adding GUI controls to enable going forward/backward interactively, in addition to play/stop the animation:
function testAnimationGUI()
%# coordinates
t = (0:.01:2*pi)'; %# 'fix SO syntax highlight
D = [cos(t) -sin(t)];
%# setup a figure and axis
hFig = figure('Backingstore','off', 'DoubleBuffer','on');
hAx = axes('Parent',hFig, 'XLim',[-1 1], 'YLim',[-1 1], ...
'Drawmode','fast', 'NextPlot','add');
axis(hAx, 'off','square')
%# draw circular path
line(D(:,1), D(:,2), 'Color',[.3 .3 .3], 'LineWidth',1);
%# initialize point
hLine = line('XData',D(1,1), 'YData',D(1,2), 'EraseMode','xor', ...
'Color','r', 'marker','.', 'MarkerSize',50);
%# init text
hTxt = text(0, 0, num2str(t(1)), 'FontSize',12, 'EraseMode','xor');
i=0;
animation = false;
hBeginButton = uicontrol('Parent',hFig, 'Position',[1 1 30 20], ...
'String','<<', 'Callback',#beginButton_callback);
hPrevButton = uicontrol('Parent',hFig, 'Position',[30 1 30 20], ...
'String','<', 'Callback',#previousButton_callback);
hNextButton = uicontrol('Parent',hFig, 'Position',[60 1 30 20], ...
'String','>', 'Callback',#nextButton_callback);
hEndButton = uicontrol('Parent',hFig, 'Position',[90 1 30 20], ...
'String','>>', 'Callback',#endButton_callback);
hSlider = uicontrol('Parent',hFig, 'Style','slider', 'Value',1, 'Min',1,...
'Max',numel(t), 'SliderStep', [10 100]./numel(t), ...
'Position',[150 1 300 20], 'Callback',#slider_callback);
hPlayButton = uicontrol('Parent',hFig, 'Position',[500 1 30 20], ...
'String','|>', 'Callback',#playButton_callback);
hStopButton = uicontrol('Parent',hFig, 'Position',[530 1 30 20], ...
'String','#', 'Callback',#stopButton_callback);
%#----------- NESTED CALLBACK FUNCTIONS -----------------
function beginButton_callback(hObj,eventdata)
updateCircle(1)
end
function endButton_callback(hObj,eventdata)
updateCircle(numel(t))
end
function nextButton_callback(hObj,eventdata)
i = i+1;
if ( i > numel(t) ), i = 1; end
updateCircle(i)
end
function previousButton_callback(hObj,eventdata)
i = i-1;
if ( i < 1 ), i = numel(t); end
updateCircle(i)
end
function slider_callback(hObj, eventdata)
i = round( get(gcbo,'Value') );
updateCircle(i)
end
function playButton_callback(hObj, eventdata)
animation = true;
while animation
i = i+1;
if ( i > numel(t) ), i = 1; end
updateCircle(i)
end
end
function stopButton_callback(hObj, eventdata)
animation = false;
end
function updateCircle(idx)
set(hSlider, 'Value', rem(idx-1,numel(t))+1) %# update slider to match
set(hLine,'XData',D(idx,1), 'YData',D(idx,2)) %# update X/Y data
set(hTxt,'String',num2str(t(idx))) %# update angle text
drawnow %# force refresh
if ~ishandle(hAx), return; end %# check valid handle
end
%#-------------------------------------------------------
end
You might find the slider functionality a bit buggy, but you get the idea :)