Toggle with one click

Thanks @benedict , those code maybe help someone in future or who want make a better version.
I am sure it is possible to add radio button and use it to switch between true and false, but without experience it is hard to make it in short time.
Good luck with your work :+1:

@seghierkhaled, after a couple of posts I noticed that you always give up just way too early. Just keep trying until you understand! Coding is not about collecting code pieces together. You have to understand how things work, at least superficial.
A grasshopper component inputs data, does some computation and outputs data again. The component attributes object is responsible for the GUI part like rendering and reacting to mouse events. If you encounter an issue, you need to identify the issue. This means you debug until you find the cause of failure. Sometimes this takes some days, sometimes its difficult to do. But the more you actually solve issues, the faster you’ll solve other problems in the future.
3 important things to do
a. pick and learn the language best-suited (in this case, C#),
b. learn to debug. How to attach a debugger to an external process and just step through code step by step. Also, logging/printing a lot is helpful. A good way to recognize logical errors.
c. read lots of code. Use ‘ILSpy’ and decompile Grasshopper to learn about its implementation details. Learn to ask more general, detailed questions. Search more on ‘Stack Overflow’, because many programming problems are already solved.

2 Likes

Thanks Tom , but this is not the case, i learn and also very busy with other things and i can’t focus on c#.
I started learn it a little from this website days ago:

Also visual studio always freeze and stop and to test a component i need to restart Rhino many times.
with python creating a component is easier to test and to compile but it is limited when we want add buttons for example.
I will focus on c# when i have time and finish my more important work.
Thank you for your advices :slight_smile:

1 Like

Hey Tom,

this sentence is just gold! I learned everything I know about coding by myself while long nights and often realize that I have many gaps in knowledge of basic coding architecture. How would I use ILSpy?

thanks in advance!!

It’s just like you have any bits and pieces together, but then you did not initialize something, or you get a null exception somewhere. Then you think it’s not working, and then you move on to another topic. I remember the discussion about Oxyplot. That was challenging. But a general approach would have been, how can I load a WPF or Eto GUI library and run it in Rhino. Once you have this, how can you make sure that it’s loaded correctly. Then what is a minimal example of Oxyplot. How can I pass values to my library and so on…

@benedict
Just download ILSpy from Github. Open the app, and drag any .Net library into it. If it’s not obfuscated, you can read the recovered source code.

Please note: decompilation for interop reasons is legal in the EU, but it’s not legal to copy and paste code or to ‘patch’ libraries with plugins like ‘Reflexil’. Some companies prohibit decompilation, but it’s not their ‘right’. I think McNeel tolerates it anyway, at least this is what I remember David Rutten saying.

Thanks Tom, with my actual knowledge in c# i can’t do more and with limitation of ironpython finding solutions sometimes is waste of time, if Rhino will support new versions of Python this will be better and make things easier.
I also hope they make a standalone app to create components with possibility to design the forms like what David did with a small app to design icons for components.

Thank you very much for this!

My goal is not to patch any libraries or steal any pieces of software, nor making money or make enterprises lose money. I am more the constructive type of person. I simply want to learn from good sources.

Though, I am happy to live in Switzerland (not EU) where I am pretty well protected in the sense that checking the activity on my computer is much more illegal than what I possibly could do by decompiling and stealing code;-) From that point of view, any enterprise would have a hard time to proof I decompiled their code without breaking into my computer and therefor laws.

I was just saying that it’s technically a gray area. Some developers are just very sensitive to this topic. But in general, it makes a huge difference on why you do these things. And there are perfectly valid reasons for it. It is a controversial topic, but the same discussion starts with Githubs ‘Codepilot’ if you heard of it. That’s in my opinion more questionable than just decompiling, disassembling code. An AI which autocompletes code for you, has been trained from real data. At some point it will just copy and paste. Although they say the opposite…

I got you. I think even Visual Studio suggested an AI to autocomplete code lately. And I understand that developpers are not very happy when they spent a lot of time, money and personal effort to obtain a good working piece of software and it will be decompiled in seconds and republished for free.
I am not a big fan of proprietary software, nor the fact that in many cases we “rent a software” nowadays, but it’s not my decision if something someone created is open source or not and I won’t force any other decision.

Thank you, Tom!

1 Like

I still need a custom color for GH_Palette (from blue to green)

image

Hi Ben, the problem with blue area is from this 3 lines

GH_PaletteStyle style = GH_Skin.palette_normal_standard;
GH_Skin.palette_normal_standard = style;
base.Render(canvas, graphics, channel);

This is an updated version of your code.
And i need to know how we can make fonts bigger? if someone know please share.

image

using System;
using System.Collections.Generic;
using Grasshopper.Kernel;
using System.Drawing;
using Grasshopper.GUI;
using Grasshopper.GUI.Canvas;
using Grasshopper.Kernel.Types;

namespace singleClick  //adapt to your project
{

    public class SpecialIntegerObject : GH_Param<GH_Boolean>
    {
        public SpecialIntegerObject() :
          base(new GH_InstanceDescription("Toggle", "Toggle", "True/False", "Params", "Input"))
        { }

        public override void CreateAttributes()
        {
            m_attributes = new SpecialIntegerAttributes(this);
        }

        protected override Bitmap Icon
        {
            get
            {
                return Toggle_new.Properties.Resources.tog;

            }
        }
        public override GH_Exposure Exposure
        {
            get
            {
                return GH_Exposure.primary | GH_Exposure.obscure;
            }
        }
        public override System.Guid ComponentGuid
        {
            get { return new Guid("{520F0976-35D1-4CC4-925B-2A07BFF17007}"); }
        }

        //private int m_value;
        private bool m_value;
        public bool Value
        {
            get { return m_value; }
            set { m_value = value; }
        }
        protected override void CollectVolatileData_Custom()
        {
            VolatileData.Clear();
            AddVolatileData(new Grasshopper.Kernel.Data.GH_Path(0), 0, new GH_Boolean(Value));
        }

        public override bool Write(GH_IO.Serialization.GH_IWriter writer)
        {
            writer.SetBoolean("SpecialInteger", m_value);
            return base.Write(writer);
        }
        public override bool Read(GH_IO.Serialization.GH_IReader reader)
        {
            reader.TryGetBoolean("SpecialInteger", ref m_value);
            return base.Read(reader);
        }
    }

    public class SpecialIntegerAttributes : GH_Attributes<SpecialIntegerObject>
    {

        public SpecialIntegerAttributes(SpecialIntegerObject owner)
          : base(owner)
        {

        }

        public override bool HasInputGrip { get { return false; } }
        public override bool HasOutputGrip { get { return true; } }

        private const int ButtonSize = 34;

        public bool bo;

        //Our object is always the same size, but it needs to be anchored to the pivot.
        protected override void Layout()
        {
            //Lock this object to the pixel grid. 
            //I.e., do not allow it to be position in between pixels.
            Pivot = GH_Convert.ToPoint(Pivot);
            Bounds = new RectangleF(Pivot, new SizeF((float)(ButtonSize * 2.5), ButtonSize));
        }
        /// <summary>
        /// This method returns the button at the given column and row offsets.
        /// </summary>
        private RectangleF TextBound()
        {
            int x = Convert.ToInt32(Pivot.X);
            int y = Convert.ToInt32(Pivot.Y);
            return new RectangleF(new PointF(x + 28, y), new SizeF(55, ButtonSize));
        }
        private Rectangle Button()
        {
            int x = Convert.ToInt32(Pivot.X);
            int y = Convert.ToInt32(Pivot.Y);
            return new Rectangle(x + 4 , y + 4, ButtonSize - 8, ButtonSize - 8);
        }
        /// <summary>
        /// Gets the value for the given button.
        /// </summary>


        public override GH_ObjectResponse RespondToMouseDown(GH_Canvas sender, GH_CanvasMouseEvent e)
        {
            //On one click we'll set the owner value.
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {

                RectangleF button = Button();
                if (button.Contains(e.CanvasLocation))
                {
                    bo = !bo;
                    Owner.RecordUndoEvent("Square Change");
                    Owner.Value = bo;
                    Owner.ExpireSolution(true);
                    return GH_ObjectResponse.Handled;
                }

            }
            return base.RespondToMouseDown(sender, e);

        }
        public override void SetupTooltip(PointF point, GH_TooltipDisplayEventArgs e)
        {
            base.SetupTooltip(point, e);
            e.Description = "Toggle";
        }

        /// <summary>
        /// This object is rendered as a 1x3 grid of capsules.
        /// </summary>

        protected override void Render(GH_Canvas canvas, Graphics graphics, GH_CanvasChannel channel)
        {
            if (channel == GH_CanvasChannel.Objects)
            {
                //Render output grip.
                GH_CapsuleRenderEngine.RenderOutputGrip(graphics, canvas.Viewport.Zoom, OutputGrip, true);

                Rectangle button = Button();
                RectangleF bound = Bounds;
                RectangleF text = TextBound();

                GH_Palette palette;

                if (Owner.Value == true)
                {
                    palette = GH_Palette.Blue;
                }
                else
                {
                    palette = GH_Palette.White;
                }

                GH_Capsule capsule = GH_Capsule.CreateTextCapsule(bound, text, GH_Palette.Black, Owner.Value.ToString(), 17, 0);
                capsule.Render(graphics, Selected, Owner.Locked, false);

                GH_Capsule buttonb = GH_Capsule.CreateCapsule(button, palette, 16, 0);
                buttonb.Render(graphics, Selected, Owner.Locked, false);

                capsule.Dispose();
            }
        }
    }
}

tog

3 Likes

yup, thank you, I just understood that 5 min ago:-)
here for everyone the gha file:

singleClick.gha (13.5 KB)

img

I dont have to render the base, but another rectangle…
I admit your solution being way more stylish than mine, but I prefer keeping the style alike :wink:

yay! good teamwork, I guess you can mark that as solved.

EDIT: Thanks for the probs, but I haven’t done big thing except for struggling and learning, haha!

2 Likes

Thank you , i still wait to know how to use green color because toggle generally use this color :slight_smile:

And the door is open to more solutions
You can share the result in food4rhino because the last one is your code , i am sure this will help many people.


Just one thing, when i save a file with Toggle = True, and open it again i need to click two times to change it to False
this happened only with True enabled

The reason i choose this style because it is easy to move the component and the Checkbox looks better than click.

I think because selected state is using green…

Thanks Ben, the solution is to set bo value.

image

Thank you @benedict for your time and your help. finally this is the component Toggle and i hope know how to change the color from blue to green.

2 Likes

The change of the color is simple :smiley:
I like this version with highlight but the problem with the white corners

image

image

color = Color.GreenYellow;
GH_Capsule buttonb = GH_Capsule.CreateCapsule(button, GH_Palette.White, 16, 0);
buttonb.Render(graphics, color);
buttonb.Dispose();

Toggle.gha (11.5 KB)

3 Likes

I try this but i don’t see any change
How to use HighlightShape and OutlineShape?

GH_Capsule buttonb = GH_Capsule.CreateCapsule(button, GH_Palette.White, 16, 1);
buttonb.Render(graphics, color);
buttonb.HighlightShape.AddEllipse(outline);
buttonb.OutlineShape.AddEllipse(outline);
buttonb.Dispose();

nice findings @seghierkhaled !! thanks!

for the highlights:

you need to empty the highlight settings before adding a new shape:

I guess outline is a rectangle in your case:

cap.HighlightShape.Reset();
cap.HighlightShape.AddEllipse(new RectangleF(Pivot, new SizeF(ButtonSize, ButtonSize)));

or even better:

capsule.HighlightShape.Reset();
capsule.HighlightShape.AddPath(capsule.OutlineShape,true);

capsule.HighlightShape.Reset();
            capsule.HighlightShape.AddPie(button, 180f, 180f);

works pretty well for round buttons:


singleClick.gha (14 KB)

1 Like