Yes, you get birthday cake for your birthday …and for any anniversary here, in a forum.
I dislike committing social faux pas. Should I be adding these to my calendar? ;^)
Absolutely, every forum member you see a cake symbol you obligated to add them (their anniversary) to your calendar… :
Now I’m worried that I may be in some trouble.
I admit that I have seen the anniversary icon in the past on a number of people’s profiles and I simply took no action. Not only did I not mention anything, but I didn’t add them to my ToDo list and I didn’t put them on my calendar. I may have neglected my own anniversary. Is it possible that I’ve been added to some kind of black list? Could my anniversary icon display privileges be revoked? Do I have to go back and commemorate all of the anniversaries I’ve neglected as a penance? I’m beginning to feel overwhelmed by the philosophical (nay, spiritual) issues that this birthday icon for forum joining anniversary commemoration topic have brough to the fore.
I already have 27345 calendar entry. Oh no, I just checked, these are not there. I am guilty! ?
James, take it easy, just ignore this “social cake” …better to focus on your original topic…
Working on Attribute Groups and Attribute Profiles. The idea is that one might develop their own commonly used attribute (visibility) groupings and then store these groups as profiles for use in other projects. It’ll save time if one uses the same group schemes across models. Attributes still need to be applied (unless they are applied to components in a library and brought in).
That’s a white color attribute. Otherwise, you can see that there is no color swatch if one is not added.
At first I removed the random (but Modus themed) color assignment and made the chips show the selected color attribute. But I removed the Modus chips because they were a little busy and I needed more features. Attributes in the list still have visibility toggling and can be selected and added to Attribute Groups. But now the Attribute Groups can have attributes added and removed.
I’m not sure about leaving attribute displays as lists. I could switch back to Modus chips later or a horizontal display for attributes in the Attribute Groups. It’s not really styled yet. For example, I’m not going to keep red highlighting for attribute selection.
But I have a couple more features to build. One is persistent storage of Attribute Profiles. The Attribute Profiles store Attribute Groups. So, for example, you could have “My Wonderful Attribute Profile” and the Attribute Groups, Levels, Ext, Int, Str, etc., saved so you don’t have to recreate them each time.
I broke it :^)!
But I’m fixing it…
Thanks for the detailed explanation! It will be a very useful extension. I hope that the functionality will allow you, in the end, to create the interface as simple and clear as possible (Modus - Chips ).
Those Modus chips are nothing but a bit of a hinderance, for now!
I was thinking that the Modus badges or cards might be another option: Cards | Trimble Modus Bootstrap Developer Guide
For example, I would probably not show the Include Color checkbox and color watch on the top level. So that could be hidden in a collapsed accordion. Also, if I add other options, or put Attribute Grouping and/or Attribute Profile assignment there (hidden), it might just be better to have a card pop up to ‘design’ the attribute.
Also, I finally noticed -where’s the link?- that there are other options (web, in-field, mobile and xr): Components (In-Field) | Trimble Modus Design System
But it’s mostly the same thing:
Long story short: I’ve simply created a mess.
I managed to get Attribute Groups and Attribute Profiles working.
Here I create a couple of Attribute Groups, toggle the visibility of groups and components with the attributes, remove an attribute from a group, then save the Attribute Groups as an Attribute Profile, close the Attribute Groups I’m done using to create the Attribute Profile, and load the Attribute Profile.
In this vid I create few more Attribute Groups and save those to another Attribute Profile (and misspell “Profile”). Then load Attribute Profiles and test Attribute Group visibility toggling.
Attribute Visibility is controlled by a users’ custom Attribute Groups stored as Attribute Profiles for later reuse!
Trying something new. Dynamic Component attribute dictionaries in an Html Dialog. It allows the user to do what can already be done using the DC extension, …because imitation is the highest form of flattery? Separate ruby, html, javasctipt & css.
Somebody needs a redraw.
Note, that a Submit button is normally used in a client → server scenario where the changes or data entered are sent to the cloud. In a local sense, the words Apply or Okay would be used.
Do you think the word “fetch” is poor here (and in the code, really) as well? I would be tempted to use “Enter” for the input fields (which output to the Ruby Console as a test that it works) and “Get” or “Update” for ‘getPrettyCode’ that will display DC attributes.
Here’s an example of these modifications:
Before - handleSubmit
# ruby 'main'
dialog.add_action_callback("handleSubmit") do |context, input_data|
# Split the input_data string into individual values
input_values = input_data.split(',')
puts "Input 1: #{input_values[0]}, Input 2: #{input_values[1]}"
end
# js
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('submitBtn').addEventListener('click', function() {
let input1 = document.getElementById('input1').value;
let input2 = document.getElementById('input2').value;
window.location.href = 'skp:handleSubmit@' + encodeURIComponent(input1 + ',' + input2);
});
});
To:
After
dialog.add_action_callback("getInputs") do |context, input_data|
# Split the input_data string into individual values
input_values = input_data.split(',')
puts "Input 1: #{input_values[0]}, Input 2: #{input_values[1]}"
end
###
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('enterBtn').addEventListener('click', function() {
let input1 = document.getElementById('input1').value;
let input2 = document.getElementById('input2').value;
window.location.href = 'skp:getInputs@' + encodeURIComponent(input1 + ',' + input2);
});
});
And ‘Fetch’, etc.
Before
#ruby 'main'
def self.fetch_dynamic_attributes(dialog)
model = Sketchup.active_model
selection = model.selection
return unless selection.length == 1
entity = selection[0]
return unless entity.is_a?(Sketchup::ComponentInstance)
dynamic_attributes = entity.attribute_dictionary("dynamic_attributes")
return unless dynamic_attributes
# Format the attributes into a string
attributes_str = dynamic_attributes.map { |key, value| "#{key}: #{value}" }.join("\n")
# Send this string back to the HTML dialog
dialog.execute_script("updateAttributes(#{attributes_str.inspect})")
end
#
dialog.add_action_callback("fetchAttributes") do |context|
fetch_dynamic_attributes(dialog)
end
#js
function updateAttributes(data) {
document.getElementById('attributesContent').textContent = data;
}
And then instead of ‘fetch’ and just ‘attributes’
After
#ruby main
def self.get_dc_attributes(dialog)
model = Sketchup.active_model
selection = model.selection
return unless selection.length == 1
entity = selection[0]
return unless entity.is_a?(Sketchup::ComponentInstance)
dynamic_attributes = entity.attribute_dictionary("dynamic_attributes")
return unless dynamic_attributes
attributes_str = dynamic_attributes.map { |key, value| "#{key}: #{value}" }.join("\n")
dialog.execute_script("updateDcAttributesDisplay(#{attributes_str.inspect})")
end
dialog.add_action_callback("getDcAttributes") do |context|
get_dc_attributes(dialog)
end
#js
function updateDcAttributesDisplay(data) {
document.getElementById('dcAttributesContent').textContent = data;
}
So “Get” or “Update” for the UI button - whichever may be best to show the user. But the code is, I hope - better / more conventional and easier to read.
Fetch is okay. But if a SelectionObserver
is used the dialog could just follow what is selected as the native DC extension does.
Okay. I’ll try that to see if I can understand it.
Okay, selection observer…
On DC selection.
Another DC, container updated.
Select non-DC, detach observer and clear container.
@DanRathbun I used an instance variable. Is that the wrong thing to do? I’m going to redo this.
NO if the variable is inside a class or module.
Thank you. Without getting too far into it (and providing a poor explanation), I had a version that I think was worse than the following. It had @dialog = UI::HtmlDialog.new, which had cascading consequences. Such as peppering the @dialog around the code.
This change keeps it inside the class.
New with instance variable inside selection observer
class DcSelectionObserver < Sketchup::SelectionObserver
def initialize(dialog)
@dialog = dialog
end
def onSelectionBulkChange(selection)
puts "Selection changed"
if selection.empty? || !selection.single_object? || !selection[0].is_a?(Sketchup::ComponentInstance) || !selection[0].attribute_dictionary("dynamic_attributes")
IDK_Programming::Dc_Ac.clear_dc_attributes_display(@dialog)
elsif selection.single_object? && selection[0].is_a?(Sketchup::ComponentInstance) && selection[0].attribute_dictionary("dynamic_attributes")
IDK_Programming::Dc_Ac.update_dc_attributes_display(@dialog, selection[0])
end
end
end
Well dialogs need to have a persistent reference, or they get garbage collected and disappear.
So, an @dialog
variable is fine.