Generate roof plugin

This topic has been viewed 2463478 times and has 338 replies
Thread status: Active
Questions about extending features and developing plug-ins [img]http://www.sweethome3d.com/images/flags/en_small.gif[/img]
User avatar
byDMA
Posts: 26
Joined: Sat Jun 08, 2024 7:29 pm
Country: GERMANY | POLAND

Re: Generate roof plugin

Post by byDMA »

So, that is the raster plan:
Image
Image
If I'm wrong let me know.

Try this:
Mac may be not correct, we will correct this later. Its experimental (replace the lines for layout):

Code: Select all

/**
	 * Layout user interface
	 * @author Daniels118 & byDMA
	 */
	protected JPanel createUI() {
		JPanel roofPanel = SwingTools.createTitledPanel(null);
		roofPanel.setBorder(null);
		// Column 0~3 Row 0~9
		roofPanel.add(roofPreview,
				new GridBagConstraints(0, 0, 4, 9, 1, 1, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
		// Column 4 Row 1
		if (OperatingSystem.isMacOSX()) {
			roofPanel.add(edgesLabel,
					new GridBagConstraints(4, 0, 2, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 10, 0, 0), 0, 0));
		}
		// Column 4+5 Row 0~7
		roofPanel.add(scrollEdgesPane,
				new GridBagConstraints(4, 0, 2, 7, 0, 0, GridBagConstraints.NORTH, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
		// Column 4+5 Row 9
		roofPanel.add(resetButton,
				new GridBagConstraints(4, 9, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		if (OperatingSystem.isMacOSX()) {
			roofPanel.add(invisibilityLabel,
					new GridBagConstraints(5, 1, 1, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 10, 0, 0), 0, 0));
		}
		// Column 6+7 Row 0
		roofPanel.add(invisibilityPane,
				new GridBagConstraints(6, 0, 2, 1, 0, 0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		// Column 6+7 Row 1~5
		roofPanel.add(faceAngleSlider,
				new GridBagConstraints(6, 1, 2, 5, 0, 1, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
		// Column 6+7 Row 6
		roofPanel.add(finePane,
				new GridBagConstraints(6, 6, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		// Column 4+5 Row 7
		roofPanel.add(thickPane,
				new GridBagConstraints(4, 7, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		// Column 6+7 Row 7
		roofPanel.add(elevationPane,
				new GridBagConstraints(6, 7, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		// Column 6+7 Row 8
		roofPanel.add(creatorPane,
				new GridBagConstraints(6, 8, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		// Column 0 Row 9
		roofPanel.add(showHome,
				new GridBagConstraints(0, 9, 1, 1, 1, 0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		// Column 2 Row 9
		roofPanel.add(showTexture,
				new GridBagConstraints(2, 9, 1, 1, 0, 0, GridBagConstraints.LINE_END, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		// Column 3 Row 9
		roofPanel.add(reverseFaces,
				new GridBagConstraints(3, 9, 1, 1, 0, 0, GridBagConstraints.LINE_END, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));		
		// Column 4+5 Row 8
		roofPanel.add(bordersPane,
				new GridBagConstraints(4, 8, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));	
		// Column 6+7 Row 9
		roofPanel.add(aboutButton,
				new GridBagConstraints(6, 9, 2, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
		
		// First refresh roof
		edgesList.updateUI();
		plugin.refreshRoof(plugin.homeView, plugin.resource);
		return roofPanel;
	}
User avatar
byDMA
Posts: 26
Joined: Sat Jun 08, 2024 7:29 pm
Country: GERMANY | POLAND

Re: Generate roof plugin

Post by byDMA »

Buttons (Reset and About) are not corect in center, we make it later, show me than the window.
User avatar
dorin
Posts: 824
Joined: Thu Apr 24, 2014 9:14 am
Country: Vatra Dornei, Suceava, Romania

Re: Generate roof plugin

Post by dorin »

Sorry for the late reaction. I have a big cervical pain for a week and it doesn't stop yet.
Your new arrangement look like this:
<DMA-01>
Image
<DMA-02>
Image
Some comments:
1. The single thing I've do was to add 2 spaces after the degree sign to make it more legible and increase the edge field (red arrow on DMA-01)
2. As you can see, to add extra rows don't change (improve) the aspect. The grid don't have a fixed size.
3. I've also used the Deutsch translations to show you how to different LaF render it.(red ellipses).
3.1. The truncated long text it's an old problem.
3.2. I'm curious how other applications have solve this in germane (LO, Blender, LibreCAD etc)
3.3. My solution was to find words as short as possible to use in titles and add some Tool tips with a large description.(eg. Thick in place of Thicknesses)
3.3.1 This has to be the translators task. For sample:Böschungsneigung could be replaced with Winkel or Feinjustierung with Fein
3.4. All this are necessary to keep an homogeneity between systems and their custom LaFs.
4. Some of my opinions about the ergonomy of a UI application:
4.1. Like in reading: from left to right and from top to bottom.
4.2. The most used near to top, continuing down with rarely used and finished with bottom OK or Cancel.
4.3. Almost all devices have a Reset button. Almost always is hard accessible to prevent accidental actions.
So, in my opinion, considering this, I put the Reset button on top right corner, away from used controls an Ok button.
I've thinking (from my personal experience), after a half of hour of work to fine tuning a roof to finally press Reset in place of Ok.
Well, most users probably aren't as old and stupid as me, but preemptively...
5. My arrangement also takes care of possible future improvements. (Look at the probably v5.0, if will ever be)
A computer program does what you tell it to do, not what you want it to do. Murphy's Law
When all else fails, read the instructions. Murphy's Law
If you don't like "AS IS", DIY. Dorin's law
User avatar
Puybaret
Posts: 9440
Joined: Mon Nov 07, 2005 12:00 pm
Country: Paris, France
Contact:

Re: Generate roof plugin

Post by Puybaret »

Dorin, get a good rest, Sweet Home 3D doesn’t worth that you get more pain [:(]
Emmanuel Puybaret, Sweet Home 3D creator
User avatar
byDMA
Posts: 26
Joined: Sat Jun 08, 2024 7:29 pm
Country: GERMANY | POLAND

Re: Generate roof plugin

Post by byDMA »

Hi Dorin, thank you, the grids are very well.

try this and SEND me privat the compiled plugin for test.
The width of the edge panel we create with list width, not spaces.

Code: Select all

package generateroof;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Event;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashSet;
import java.util.ResourceBundle;
import java.util.Set;

import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import com.eteks.sweethome3d.model.HomeMaterial;
import com.eteks.sweethome3d.model.UserPreferences;
import com.eteks.sweethome3d.swing.AutoCommitSpinner;
import com.eteks.sweethome3d.swing.ModelPreviewComponent;
import com.eteks.sweethome3d.swing.NullableCheckBox;
import com.eteks.sweethome3d.swing.NullableSpinner;
import com.eteks.sweethome3d.swing.SwingTools;
import com.eteks.sweethome3d.swing.NullableSpinner.NullableSpinnerLengthModel;
import com.eteks.sweethome3d.tools.OperatingSystem;
import com.eteks.sweethome3d.viewcontroller.HomeView;

public class GenrateRoofPluginView {
	private final GenerateRoofPlugin plugin;

	public GenrateRoofPluginView(GenerateRoofPlugin generateRoofPlugin) {
		this.plugin = generateRoofPlugin;
	}

	float resolutionScale = SwingTools.getResolutionScale();
	ModelPreviewComponent roofPreview;
	ChangeListener commonListener;
	ListSelectionListener edgesListener;
	NullableCheckBox invisibilityCheck, showHome, showTexture, reverseFaces;
	JSlider faceAngleSlider;
	JRadioButton verticalBorder, orthoBorder;
	ImageIcon vertIcon, vertSelIcon, orthoIcon, orthoSelIcon;
	ButtonGroup borderGroupBtn;
	JButton resetButton, aboutButton;
	NullableSpinnerLengthModel thickModel, roofElevationModel;
	NullableSpinner thick, roofElevation;
	JSpinner fineSlope;
	JList<SlopedEdge> edgesList;
	JScrollPane scrollEdgesPane;
	JTextField creator;
	JLabel edgesLabel, invisibilityLabel;
	JPanel invisibilityPane, slopePane, bordersPane, finePane, thickPane, elevationPane, creatorPane;

	/**
	 * Creates and layout the components shown in the dialog box of this plug-in.
	 * 
	 * @author Daniels118
	 * 
	 * @param homeView
	 * @param resource
	 */
	protected void createComponents(final HomeView homeView, final ResourceBundle resource) {
		UserPreferences preferences = plugin.getUserPreferences();
		String unitName = preferences.getLengthUnit().getName();

		// Create a common change listener for some components.
		commonListener = new ChangeListener() {
			@Override
			public void stateChanged(ChangeEvent ev) {
				if (ev.getSource().equals(showHome)) {
					if (showHome.getValue()) {
						plugin.homeItems.removeAllChildren();
						plugin.homeItems = plugin.createHomeNode(plugin.getHome());
					}
					plugin.refreshRoof(homeView, resource);

				} else if (ev.getSource().equals(faceAngleSlider)) {
					int slope = faceAngleSlider.getValue();
					int maxAngle = faceAngleSlider.getMaximum() - 1;
					// Limit the slope in range 1 to 179 degrees
					slope = slope > 1 ? slope : 1;
					slope = slope < maxAngle ? slope : maxAngle;
					// Update the angle for the selected faces
					for (SlopedEdge edge : edgesList.getSelectedValuesList())
						edge.setSlope(slope);
					fineSlope.removeChangeListener(commonListener);
					fineSlope.setValue(0.0);
					fineSlope.addChangeListener(commonListener);
					if (!faceAngleSlider.getValueIsAdjusting() && faceAngleSlider.hasFocus()) {
						edgesList.updateUI();
						plugin.updateSelectedFacesFromList(homeView, resource);
					}
				} else if (ev.getSource().equals(fineSlope)) {
					// Add the fine tuning to edge slope
					float fineSlopeVal = ((Number) fineSlope.getValue()).floatValue();
					float angle = faceAngleSlider.getValue();
					float maxAngle = faceAngleSlider.getMaximum() - 1;
					float slope = angle + fineSlopeVal;
					slope = slope > 1f ? slope : 1.0f;
					slope = slope < maxAngle ? slope : maxAngle;
					// Update the angle for the selected faces
					for (SlopedEdge edge : edgesList.getSelectedValuesList())
						edge.setSlope(slope);
					edgesList.updateUI();
					plugin.updateSelectedFacesFromList(homeView, resource);
				} else if (ev.getSource().equals(invisibilityCheck)) {
					if (invisibilityCheck.getValue() != null) {
						boolean visible = !invisibilityCheck.getValue();
						// Update the face visibility
						for (SlopedEdge edge : edgesList.getSelectedValuesList())
							edge.setFaceVisible(visible);
						edgesList.updateUI();
						plugin.updateSelectedFacesFromList(homeView, resource);
					}
				} else {
					plugin.refreshRoof(homeView, resource);
				}
			}
		};

		// Create edges list selection listener.
		edgesListener = new ListSelectionListener() {
			@Override
			public void valueChanged(ListSelectionEvent ev) {
				int edgeSelection = edgesList.getSelectedIndices().length;
				// Limit selection to have at least one face with slope < 90 deg
				int maxAngle = edgeSelection < plugin.allRoofEdges.length ? 180 : 76;
				if (faceAngleSlider.getMaximum() != maxAngle)
				   faceAngleSlider.setMaximum(maxAngle);
				SlopedEdge edge = edgesList.getSelectedValue();
				if (edge != null) {
					// Set angle
					faceAngleSlider.removeChangeListener(commonListener);
					faceAngleSlider.setValue((int) edge.getSlope());
					faceAngleSlider.addChangeListener(commonListener);
					// Set fine slope
					fineSlope.removeChangeListener(commonListener);
					fineSlope.setValue(edge.getSlope() - faceAngleSlider.getValue());
					fineSlope.addChangeListener(commonListener);
				}
				if (!ev.getValueIsAdjusting() && edgesList.hasFocus())
				   plugin.updateSelectedFacesFromList(homeView, resource);
			}
		};
		// Create preview
		roofPreview = new ModelPreviewComponent(true, true, true, true);
		roofPreview.setFocusable(false);
		roofPreview.setPreferredSize(new Dimension((int) (800 * resolutionScale), (int) (600 * resolutionScale)));// @byDMA resizing window to 800x600
		// Add a mouse listener to get selected faces
		roofPreview.addMouseListener(new MouseAdapter() {
			private Set<SlopedEdge> selectedEdges = new HashSet<SlopedEdge>();// Using a set avoids duplicates

			@Override
			public void mouseClicked(MouseEvent ev) {
				HomeMaterial pickedMaterial = roofPreview.getPickedMaterial();
				boolean sInterval = false;
				if (pickedMaterial != null) {
					String faceName = pickedMaterial.getName();
					for (RoofFace face : plugin.faces) {
						if (faceName.equals(face.getFaceName())) {
							if ((ev.getModifiers() & Event.CTRL_MASK) != 0 || (ev.getModifiers() & Event.SHIFT_MASK) != 0) {
								for (SlopedEdge sEdge : face.getGeneratingEdges()) {
									if (!selectedEdges.add(sEdge))
									   selectedEdges.remove(sEdge);// Toggle selection
								}
								if ((ev.getModifiers() & Event.SHIFT_MASK) != 0)
								   sInterval = true;
							} else {
								selectedEdges.clear();
								for (SlopedEdge sEdge : face.getGeneratingEdges())
									selectedEdges.add(sEdge);
							}
							break;// There can be a single face matching the picked material
						}
					}
					int[] edgeIndices = new int[selectedEdges.size()];
					int i = 0;
					for (SlopedEdge sEdge : selectedEdges)
						edgeIndices[i++] = sEdge.getEdge();
					edgesList.setSelectedIndices(edgeIndices);
					int sMin = edgesList.getMinSelectionIndex();
					int sMax = edgesList.getMaxSelectionIndex();
					if (sInterval)
					   edgesList.addSelectionInterval(sMin, sMax);
					if (i > 0)
					   edgesList.ensureIndexIsVisible(edgeIndices[i - 1]);
				} else if ((ev.getModifiers() & Event.CTRL_MASK) == 0) {
					edgesList.setSelectedIndices(new int[0]);// Deselect when click the background
				}
				edgesList.updateUI();
				plugin.updateSelectedFacesFromList(homeView, resource);
			}
		});

		// Create edges list
//		String edgesLabel = resource.getString("edges.txt");// Edges: Slope
		edgesList = new JList<SlopedEdge>();
		edgesList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
		edgesList.setListData(plugin.allRoofEdges);// Add edges to the list
		edgesList.setCellRenderer(new EdgesCellRenderer());
		edgesList.addListSelectionListener(edgesListener);
		edgesList.setFixedCellWidth(140);// byDMA resize width of the List in the JScrollPane
		// Put edges list into scroll panel
		String edgesLab = resource.getString("edges.txt");// Edges: Slope
		edgesLabel = new JLabel(edgesLab);// Edges: Slope
//		scrollEdges = SwingTools.createScrollPane(edgesList);
		scrollEdgesPane = new JScrollPane(edgesList);
		if (OperatingSystem.isMacOSX()) {
			Dimension preferredSize = scrollEdgesPane.getPreferredSize();
			scrollEdgesPane.setPreferredSize(new Dimension(Math.min(200, preferredSize.width), preferredSize.height));
		} else {
			
			scrollEdgesPane.setBorder(new TitledBorder(edgesLabel.getText()));
		}

		// Create slope slider
		String slopeSliderLabel = resource.getString("slope.txt");// Slope
		faceAngleSlider = new JSlider(JSlider.VERTICAL, 0, 180, 40);
		faceAngleSlider.setPaintTicks(true);
		faceAngleSlider.setPaintLabels(true);
		faceAngleSlider.setMajorTickSpacing(30);
		faceAngleSlider.setMinorTickSpacing(5);
		faceAngleSlider.setBorder(new TitledBorder(slopeSliderLabel));
		faceAngleSlider.addChangeListener(commonListener);

		// Create fine slope angle spinner
		SpinnerNumberModel fineSlopeModel = new SpinnerNumberModel(.0, -0.9, 0.9, .1);
		fineSlope = new AutoCommitSpinner(fineSlopeModel);
		fineSlope.addChangeListener(commonListener);
		// Fine angle panel
		String fineSlopeShort = resource.getString("fineSlope.txt");// Fine slope
		finePane = SwingTools.createTitledPanel(fineSlopeShort);
		finePane.add(fineSlope);

		// Create face invisibility check box
		String invisibility = resource.getString("invisibility.txt");// Invisible
		invisibilityCheck = new NullableCheckBox(invisibility);
		invisibilityCheck.setNullable(false);
		invisibilityCheck.setValue(false);
		invisibilityCheck.addChangeListener(commonListener);
		// Invisibility check panel
		String faceVisible = resource.getString("face.txt");// Face
		invisibilityLabel = new JLabel(faceVisible);
		if (OperatingSystem.isMacOSX()) {
			invisibilityPane = SwingTools.createTitledPanel(null);
		} else {
			invisibilityPane = SwingTools.createTitledPanel(invisibilityLabel.getText());
		}
		invisibilityPane.add(invisibilityCheck);

		// Create roof border thickness spinner
		String thickLong = String.format(resource.getString("thickness.txt"), unitName);// Roof thickness
		thickModel = new NullableSpinnerLengthModel(preferences, 7.6f, 2.5f, 30.5f);
		thick = new NullableSpinner(thickModel);
		thick.setToolTipText(thickLong);
		// Thickness panel
		String thickShort = String.format(resource.getString("thick.txt"), unitName);// Thick
		thickPane = SwingTools.createTitledPanel(thickShort);
		thickPane.add(thick);
		if (plugin.isRoofSelected()) {
			String sThickness = plugin.currentRoof.getProperty(GenerateRoofPlugin.ROOF_THICKNESS);
			if (sThickness != null) {
				float currentThick = Float.valueOf(sThickness);
				try {
					thickModel.setLength(currentThick);
				} catch (Exception e) {
					/**
					 * @author Daniels118 No need to translate this message, only "hackers" have
					 *         chances to see it
					 */
					plugin.getHomeController().getView().showError("Cannot retrieve thickModel: " + e.getMessage());
				}
			}
		}
		thickModel.addChangeListener(commonListener);

		// Create roof elevation spinner
		String elevationLong = String.format(resource.getString("roofelevation.txt"), unitName);// Elevate roof at needed position
		roofElevationModel = new NullableSpinnerLengthModel(preferences, 0.0f, 0.0f, 9999f);
		roofElevation = new NullableSpinner(roofElevationModel);
		roofElevation.setToolTipText(elevationLong);
		roofElevationModel.setLength(plugin.getRoofElevation(plugin.currentLevel));
		roofElevationModel.addChangeListener(commonListener);
		// Elevation panel
		String elevationShort = String.format(resource.getString("elevation.txt"), unitName);// Elevation(%s)
		elevationPane = SwingTools.createTitledPanel(elevationShort);
		elevationPane.add(roofElevation);

		// Create home visibility check box
		String displayHome = resource.getString("displayHomeCheckBox.txt");// Show home
		showHome = new NullableCheckBox(displayHome);
		showHome.setValue(false);
		showHome.addChangeListener(commonListener);

		// Create texture visibility check box
		String useTexture = resource.getString("displayTextureCheckBox.txt");// Use roof texture
		showTexture = new NullableCheckBox(useTexture);
		showTexture.setValue(false);
		showTexture.setEnabled(plugin.isRoofSelected());
		showTexture.addChangeListener(commonListener);

		// Create reverse faces check box
		String reverseFacesTxt = resource.getString("reverseFaces.txt");// Reverse faces
		reverseFaces = new NullableCheckBox(reverseFacesTxt);
		reverseFaces.setValue(false);
		reverseFaces.addChangeListener(commonListener);

		// Create creator field
		String author = System.getProperty("user.name");
		if (plugin.isRoofSelected())
		   author = plugin.currentRoof.getCreator();
		creator = new JTextField(author);
		creator.setEditable(true);
		// @byDMA 2. store default height for TextField creator
		int defaultHeight = creator.getSize().getHeight();
		// @byDMA 3. set custom width and default height
		creator.setSize(new Dimension(250, defaultHeight));

		// Creator panel
		String authorText = resource.getString("authorText.txt");// Creator
		creatorPane = SwingTools.createTitledPanel(authorText);
		creatorPane.add(creator);

		// Create borders radio buttons
		vertIcon = new ImageIcon(GenerateRoofPlugin.class.getResource("/generateroof/resources/vert.png"));
		vertSelIcon = new ImageIcon(GenerateRoofPlugin.class.getResource("/generateroof/resources/vertSel.png"));
		orthoIcon = new ImageIcon(GenerateRoofPlugin.class.getResource("/generateroof/resources/ortho.png"));
		orthoSelIcon = new ImageIcon(GenerateRoofPlugin.class.getResource("/generateroof/resources/orthoSel.png"));
		// Vertical border button
		verticalBorder = new JRadioButton(vertIcon, true);// default selected
		verticalBorder.setActionCommand("vertical");
		verticalBorder.setSelectedIcon(vertSelIcon);
		// Orthogonal border button
		orthoBorder = new JRadioButton(orthoIcon);
		orthoBorder.setActionCommand("orthoUp");
		orthoBorder.setSelectedIcon(orthoSelIcon);
		// Group border direction buttons
		borderGroupBtn = new ButtonGroup();
		borderGroupBtn.add(verticalBorder);
		borderGroupBtn.add(orthoBorder);
		// Border orientation panel
		String borders = resource.getString("borderText.txt");// Border
		bordersPane = SwingTools.createTitledPanel(borders);
		bordersPane.add(verticalBorder, 0);
		bordersPane.add(orthoBorder, 1);
		// Set initial border
		if (plugin.isRoofSelected()) {
			String dirThick = plugin.getSelectedRoof().getProperty(GenerateRoofPlugin.ROOF_THICKNESS_DIRECTION);
			if (dirThick != null) {
				try {
					if (orthoBorder.getActionCommand().equals(dirThick))
					   borderGroupBtn.setSelected(orthoBorder.getModel(), true);
				} catch (Exception e) {
					/**
					 * @author Daniels118 No need to translate this message, only "hackers" have
					 *         chances to see it
					 */
					plugin.getHomeController().getView().showError("Cannot retrieve direction: " + e.getMessage());
				}
			}
		}
		// Create a listener for the border buttons.
		ActionListener borderActionListener = new ActionListener() {
			public void actionPerformed(ActionEvent actionEvent) {
				AbstractButton aButton = (AbstractButton) actionEvent.getSource();
				if (aButton.isSelected())
				   plugin.refreshRoof(homeView, resource);
			}
		};
		// Register a listener for the borders buttons.
		verticalBorder.addActionListener(borderActionListener);
		orthoBorder.addActionListener(borderActionListener);

		// Create reset button
		resetButton = new JButton(new AbstractAction(resource.getString("resetButton.txt")) {
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent ev) {
				faceAngleSlider.setValue(40);
				fineSlope.setValue(0.0);
				thickModel.setLength(7.6f);
				edgesList.setSelectedIndices(new int[0]);
				invisibilityCheck.setNullable(false);
				invisibilityCheck.setValue(false);
				invisibilityCheck.setValue(false);
				// Reset the angle for all faces to 40 deg
				int slope = faceAngleSlider.getValue();
				for (int i = 0; i < plugin.allRoofEdges.length; i++) {
					plugin.allRoofEdges[i].setSlope(slope);
					plugin.allRoofEdges[i].setFaceVisible(true);
				}
				// Reset the author
				String author = System.getProperty("user.name");
				creator.setText(author);
				// Reset the borders
				borderGroupBtn.setSelected(verticalBorder.getModel(), true);
				edgesList.updateUI();
				plugin.updateSelectedFacesFromList(homeView, resource);
			}
		});
		resetButton.setToolTipText(resource.getString("resetButtonInf.txt"));

		// About button
		aboutButton = new JButton(new AbstractAction(resource.getString("aboutButton.txt")) {
			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent ev) {
				HTMLViewer viewer = new HTMLViewer();
				viewer.addErrorListener(new HTMLViewer.ErrorListener() {
					@Override
					public void onError(Exception e) {
						e.printStackTrace();
						SwingUtilities.invokeLater(new Runnable() {
							@Override
							public void run() {
								try {
									viewer.setPage(GenerateRoofPlugin.class.getResource("/generateroof/resources/about.html"));
								} catch (IOException e1) {
									e1.printStackTrace();
								}
							}
						});
					}
				});
				try {
					String lang = resource.getLocale().getLanguage();
					String version = plugin.getVersion();
					String url = "https://daniels118.altervista.org/sh3d/roofgenerator/about/" + "?lang=" + lang + "&ver="
					      + URLEncoder.encode(version, "UTF8");
					viewer.setPage(url);
				} catch (IOException e) {
					e.printStackTrace();
				}
				JScrollPane scrollPane = new JScrollPane(viewer);
				JOptionPane helpPanel = new JOptionPane(scrollPane, JOptionPane.PLAIN_MESSAGE, JOptionPane.DEFAULT_OPTION);
				JDialog aboutDialog = helpPanel.createDialog((JComponent) homeView, resource.getString("ROOF_GEN.title"));
				aboutDialog.applyComponentOrientation(((JComponent) homeView).getComponentOrientation());
				aboutDialog.setLocationByPlatform(true);
				aboutDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
				aboutDialog.setResizable(true);
				aboutDialog.setMinimumSize(new Dimension(600, 700));
				aboutDialog.setVisible(true);
			}
		});
		//aboutButton.setBackground(Color.green);  //standard button, not green
		aboutButton.setToolTipText(resource.getString("aboutButton_Warn.txt"));
	}

	/**
	 * Layout user interface
	 * @author Daniels118 & byDMA
	 */
	protected JPanel createUI() {
		JPanel roofPanel = SwingTools.createTitledPanel(null);
		roofPanel.setBorder(null);
		// Column 0~3 Row 0~9
		roofPanel.add(roofPreview,
				new GridBagConstraints(0, 0, 4, 9, 1, 1, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
		// Column 4 Row 1
		if (OperatingSystem.isMacOSX()) {
			roofPanel.add(edgesLabel,
					new GridBagConstraints(4, 0, 2, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 10, 0, 0), 0, 0));
		}
		// Column 4+5 Row 0~7
		roofPanel.add(scrollEdgesPane,
				new GridBagConstraints(4, 0, 2, 7, 0, 0, GridBagConstraints.NORTH, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
		// Column 4+5 Row 9
		roofPanel.add(resetButton,
				new GridBagConstraints(4, 9, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		if (OperatingSystem.isMacOSX()) {
			roofPanel.add(invisibilityLabel,
					new GridBagConstraints(5, 1, 1, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 10, 0, 0), 0, 0));
		}
		// Column 6+7 Row 0
		roofPanel.add(invisibilityPane,
				new GridBagConstraints(6, 0, 2, 1, 0, 0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		// Column 6+7 Row 1~5
		roofPanel.add(faceAngleSlider,
				new GridBagConstraints(6, 1, 2, 5, 0, 1, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
		// Column 6+7 Row 6
		roofPanel.add(finePane,
				new GridBagConstraints(6, 6, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		// Column 4+5 Row 7
		roofPanel.add(thickPane,
				new GridBagConstraints(4, 7, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		// Column 6+7 Row 7
		roofPanel.add(elevationPane,
				new GridBagConstraints(6, 7, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		// Column 6+7 Row 8
		roofPanel.add(creatorPane,
				new GridBagConstraints(6, 8, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		// Column 0 Row 9
		roofPanel.add(showHome,
				new GridBagConstraints(0, 9, 1, 1, 1, 0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		// Column 2 Row 9
		roofPanel.add(showTexture,
				new GridBagConstraints(2, 9, 1, 1, 0, 0, GridBagConstraints.LINE_END, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		// Column 3 Row 9
		roofPanel.add(reverseFaces,
				new GridBagConstraints(3, 9, 1, 1, 0, 0, GridBagConstraints.LINE_END, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));		
		// Column 4+5 Row 8
		roofPanel.add(bordersPane,
				new GridBagConstraints(4, 8, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));	
		// Column 6+7 Row 9
		roofPanel.add(aboutButton,
				new GridBagConstraints(6, 9, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		
		// First refresh roof
		edgesList.updateUI();
		plugin.refreshRoof(plugin.homeView, plugin.resource);
		return roofPanel;
	}

	private class EdgesCellRenderer extends DefaultListCellRenderer {

		private static final long	serialVersionUID	= 1L;
		final ImageIcon				eyeCloseIcon		= new ImageIcon(GenerateRoofPlugin.class.getResource("/generateroof/resources/closed-eye.png"));
		final ImageIcon				emptyIcon			= new ImageIcon(GenerateRoofPlugin.class.getResource("/generateroof/resources/emptyIcon.png"));

		@Override
		public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
			String s = value.toString();
			setText(s);
			boolean visible = plugin.allRoofEdges[index].isFaceVisible();
			setIcon(!visible ? eyeCloseIcon : emptyIcon);

			if (isSelected) {
				setBackground(list.getSelectionBackground());
				setForeground(list.getSelectionForeground());
			} else {
				setBackground(list.getBackground());
				setForeground(list.getForeground());
			}

			setEnabled(list.isEnabled());
			setFont(list.getFont());
			setOpaque(true);
			return this;
		}

	}

}
User avatar
byDMA
Posts: 26
Joined: Sat Jun 08, 2024 7:29 pm
Country: GERMANY | POLAND

Re: Generate roof plugin

Post by byDMA »

it is a hole file GenerateRoofPluginView.java

I have changed the:
1. windows size to 800x600
2. about button
3. Edge-Panel list width -> should resize the scroll panel width
4. autor TextField -> set manually width to 250, this should resize the columns width 6-7
User avatar
dorin
Posts: 824
Joined: Thu Apr 24, 2014 9:14 am
Country: Vatra Dornei, Suceava, Romania

Re: Generate roof plugin

Post by dorin »

@1. The preview size you've propose could be good.
@2. The About button will remain GREEN for my public versions.
Some people could receive a customized version.
@3. Could be a solution but it is away too wide for other languages.
A compromise could be to replace Edges:Slope (Kanten: Neigung) text with only Edges (Kanten).
Another solution could be to replace JList with JTable or Jeks and include a header.
The invisibility checkbox could be also added for every edge to replace the eye indicator.
@4. This setting has not the expected effect.
it is a hole file GenerateRoofPluginView.java

You've modified few lines: 177, 231, 344(// Need cast int), 346,
421, 422 (//Wrong), 478.
For the above lines was enough to make proposal like in patches.
For the createUI method it's Ok to post it entirely as you've done in the paste.

I hope to not upset you. I'm not a programmer so my opinion don't count too much.
A computer program does what you tell it to do, not what you want it to do. Murphy's Law
When all else fails, read the instructions. Murphy's Law
If you don't like "AS IS", DIY. Dorin's law
User avatar
byDMA
Posts: 26
Joined: Sat Jun 08, 2024 7:29 pm
Country: GERMANY | POLAND

Re: Generate roof plugin

Post by byDMA »

Dorin, may be you can create a repository by sourceforge?
User avatar
Puybaret
Posts: 9440
Joined: Mon Nov 07, 2005 12:00 pm
Country: Paris, France
Contact:

Re: Generate roof plugin

Post by Puybaret »

byDMA, creating a repository is probably not something that will help Dorin to rest and recover at the moment. I already asked him in the past if he could improve the layout of his plug-in to make it more compliant under macOS, something that he performed very gently.
Maybe, we shouldn’t ask him perfection and anyway, the look and feel of a user interface always depends on one’s taste.
Emmanuel Puybaret, Sweet Home 3D creator
User avatar
byDMA
Posts: 26
Joined: Sat Jun 08, 2024 7:29 pm
Country: GERMANY | POLAND

Re: Generate roof plugin

Post by byDMA »

So, here we are. I compiled it myself and experimented with the sizes. Now it does not matter which language is used and how long or short the words are in the TittledBorder. There is no need to do tricks with the words when translating. I also tried to distribute the components and the distances evenly.
Image
Image
Image
Image

Only this is needed:
1. fix width of the edgeList

Code: Select all

edgesList.setFixedCellWidth(200);// byDMA resize width of the List in the JScrollPane
2. corrected grids
explained: ipadx changes the width of JScrollPanel with the EdgeList.
scrollEdgesPane -> 200
faceAngleSlider -> 125

Code: Select all

*/
	//TODO byDMA
	/**
    * Layout user interface
    * @author Daniels118 & byDMA
    */
   protected JPanel createUI() {
           JPanel roofPanel = SwingTools.createTitledPanel(null);
           roofPanel.setBorder(null);
           // Column 0~3 Row 0~9
           roofPanel.add(roofPreview,
                           new GridBagConstraints(0, 0, 4, 9, 1, 1, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
           // Column 4 Row 1
           if (OperatingSystem.isMacOSX()) {
                   roofPanel.add(edgesLabel,
                                   new GridBagConstraints(4, 0, 2, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 10, 0, 0), 0, 0));
           }
           // Column 4+5 Row 0~7
           roofPanel.add(scrollEdgesPane,
                           new GridBagConstraints(4, 0, 2, 7, 0, 0, GridBagConstraints.NORTH, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 200, 0));
           // Column 4+5 Row 9
           roofPanel.add(resetButton,
                           new GridBagConstraints(4, 9, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(15, 0, 0, 5), 0, 0));
           if (OperatingSystem.isMacOSX()) {
                   roofPanel.add(invisibilityLabel,
                                   new GridBagConstraints(5, 1, 1, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 10, 0, 0), 0, 0));
           }
           // Column 6+7 Row 0
           roofPanel.add(invisibilityPane,
                           new GridBagConstraints(6, 0, 2, 1, 0, 0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 15));
           // Column 6+7 Row 1~5
           roofPanel.add(faceAngleSlider,
                           new GridBagConstraints(6, 1, 2, 5, 0, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 125, 0));
           // Column 6+7 Row 6
           roofPanel.add(finePane,
                           new GridBagConstraints(6, 6, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(10, 0, 0, 0), 0, 15));
           // Column 4+5 Row 7
           roofPanel.add(thickPane,
                           new GridBagConstraints(4, 7, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(10, 0, 0, 0), 0, 15));
           // Column 6+7 Row 7
           roofPanel.add(elevationPane,
                           new GridBagConstraints(6, 7, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(10, 0, 0, 0), 0, 15));
           // Column 6+7 Row 8
           roofPanel.add(creatorPane,
                           new GridBagConstraints(6, 8, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 0, 0));
           // Column 0 Row 9
           roofPanel.add(showHome,
                           new GridBagConstraints(0, 9, 1, 1, 1, 0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(15, 0, 0, 0), 0, 0));
           // Column 2 Row 9
           roofPanel.add(showTexture,
                           new GridBagConstraints(2, 9, 1, 1, 0, 0, GridBagConstraints.LINE_END, GridBagConstraints.HORIZONTAL, new Insets(15, 0, 0, 15), 0, 0));
           // Column 3 Row 9
           roofPanel.add(reverseFaces,
                           new GridBagConstraints(3, 9, 1, 1, 0, 0, GridBagConstraints.LINE_END, GridBagConstraints.HORIZONTAL, new Insets(15, 0, 0, 15), 0, 0));
           // Column 4+5 Row 8
           roofPanel.add(bordersPane,
                           new GridBagConstraints(4, 8, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(10, 0, 0, 0), 0, 0));
           // Column 6+7 Row 9
           roofPanel.add(aboutButton,
                           new GridBagConstraints(6, 9, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(15, 5, 0, 0), 0, 0));

           // First refresh roof
           edgesList.updateUI();
           plugin.refreshRoof(plugin.homeView, plugin.resource);
           return roofPanel;
   }

Post Reply New Topic

Who is online

Users browsing this forum: No registered users and 2 guests