Page 1 of 1

How make it?

PostPosted: Mon Nov 11, 2019 11:45 am
by Silvio.Falconi
I saw on another application this
Image

the button open a menu popup and on the menu there are two slider controls , Can make it on Fwh ?

Re: How make it?

PostPosted: Mon Nov 11, 2019 7:05 pm
by ukoenig
Silvio,

You can connect a dialog to the button on action.
Dialog-top = button-bottom, dialog-left = button-left.
There You can include what ever You want.
If needed You can paint a colored border around the dialog.
The logic can be used on any other object.
In xBrowse it is connected to a cell.

Image

connecting the dialog to the button ( main function )

// --------------
...
...
DEFINE DIALOG oDlg1 FROM 0, 0 TO 180, 200 OF oDlg PIXEL TRUEPIXEL FONT oFont ;
STYLE WS_POPUP
...
@ 20, 30 BTNBMP oBtn1 2007 ;
SIZE 30, 30 OF oDlg NOBORDER ;
ACTION MYDLG( oDlg, oBtn1, oFont )
...
ACTIVATE DIALOG oDlg CENTERED

RETURN NIL

// --------------

FUNCTION MYDLG( oDlg, oBtn, oFont )
LOCAL oDlg1, oBtn2, oSlider1, nSlidPos1 := 1, oSlider2, nSlidPos2 := 2
LOCAL oRect1 := oDlg:GetRect()
LOCAL nTop1 := oRect1:nTop
LOCAL nLeft1 := oRect1:nLeft
LOCAL nTop2 := oBtn:nTop() + oBtn:nHeight() + 25 // 25 = dlg-title
LOCAL nLeft2 := oBtn:nLeft()

DEFINE DIALOG oDlg1 FROM 0, 0 TO 180, 200 OF oDlg PIXEL TRUEPIXEL FONT oFont ;
STYLE WS_POPUP

@ 20, 20 SLIDER oSlider1 VAR nSlidPos1 OF oDlg1 ;
HORIZONTAL ;
RANGE 0, 10 ;
COLORS CLR_RED, CLR_HGRAY, CLR_CYAN ;
MARKS 10 ;
SIZE 160, 35 PIXEL UPDATE
oSlider1:SetFont( oFont )

@ 80, 20 SLIDER oSlider2 VAR nSlidPos2 OF oDlg1 ;
HORIZONTAL ;
RANGE 0, 10 ;
COLORS CLR_RED, CLR_HGRAY, CLR_CYAN ;
MARKS 10 ;
SIZE 160, 35 PIXEL UPDATE
oSlider2:SetFont( oFont )

ACTIVATE DIALOG oDlg1 ;
ON INIT oDlg1:Move( nTop1 + nTop2, nLeft1 + nLeft2, , , .t. )

RETURN NIL

best regards
Uwe :D

Re: How make it?

PostPosted: Tue Nov 12, 2019 8:08 am
by Silvio.Falconi
Uwe,
If I wanted a dialog I already knew how to do it
I think I asked for a particular thing
If you look closely you will see that the button opens a POPUP MENU control
and therefore not a dialog
other times you've already answered with other things that I don't even think about asking!!!!

Re: How make it?

PostPosted: Tue Nov 12, 2019 8:32 am
by ukoenig
Silvio,

the button open a menu popup and on the menu there are two slider controls


in case something is not possible I'm looking for a alternative solution
that comes close to the needed result.

other times you've already answered with other things that I don't even think about asking!!!!


Trying to find a solution It is not a answer to something else.
But never mind I can save my time.

regards
Uwe

Re: How make it?

PostPosted: Tue Nov 12, 2019 9:07 am
by Silvio.Falconi
please,
Code: Select all  Expand view
#include "Fivewin.ch"
#include "Slider.ch"

Function Test()

Local aget[10]
Local oDlgTest
Local oFont
Local oBtn1

DEFINE FONT oFont NAME "TAHOMA" SIZE 0,-12 BOLD


DEFINE DIALOG oDlgTest FROM 0, 0 TO 180, 200  PIXEL TRUEPIXEL FONT oFont


@ 20, 30 BUTTON oBtn1 PROMPT "%" ;
SIZE 30, 30  PIXEL OF oDlgTest



oBtn1:bRClicked := {|nRow,nCol| MyPercentuale2(oBtn1,aget,oDlgTest,oFont,nRow,nCol) }




ACTIVATE DIALOG oDlgTest CENTERED

RETURN NIL

//-------------------------------------------------------------------------//


Function MyPercentuale2(oBtn,aget,oDlg,oFont,nRow,nCol)

 Local oMyoMenu
 Local aItem[4]
 Local nSconto_Percentuale := 0.00
 Local nSconto_Giorni:= 0

 bAction1 :=Sliders(aItem[1])
 bAction3 :=Sliders(aItem[3])

      MENU  oMyoMenu POPUP
         MENUITEM aItem[1] PromPt "Slider 1" // BLOCK bAction1
         MENUITEM aItem[2] PromPt "Sconto giorni :" + Ltrim(str(nSconto_Giorni))
         MENUITEM aItem[3] PromPt "Slider 3"  BLOCK bAction3
         MENUITEM aItem[4] PromPt "Sconto percentuale :"+ Ltrim(str(nSconto_Percentuale))
       ENDMENU


  ACTIVATE POPUP oMyoMenu OF oDlg AT  oBtn:nTop+nRow, oBtn:nLeft+nCol

   RETURN (NIL)




Function Sliders(aItem)
   Local oSlider1
   Local nSlidPos1 := 1

    @ 60, 20 SLIDER oSlider1 VAR nSlidPos1 OF aItem ;
                 HORIZONTAL ;
                 RANGE 0, 10 ;
                 COLORS CLR_RED, CLR_HGRAY, CLR_CYAN ;
                 MARKS 10 ;
                 SIZE 160, 35 PIXEL UPDATE
 return nil










 




I'm searching if I can make a codeblock type bInit to run a function to insert the slider into menuitem of menupopup

I found some question on Internet
https://stackoverflow.com/questions/39890861/how-to-place-horizontal-slider-in-nsmenu-swift-3-xcode-8
https://www.codeproject.com/Articles/26924/WPF-Slider-Menu

I found a source someone can converte it to fwh (https://www.codeproject.com/Articles/26 ... lider-Menu)

Code: Select all  Expand view
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Markup;
using System.IO;
using System.Reflection;
using System.Windows.Media;
using System.Diagnostics;
using System.Windows.Controls.Primitives;

namespace SliderMenu
{
    public partial class SliderMenuItem : MenuItem
    {
        private const double ThumbHeight = 11.0d;
        private Slider m_Slider;
        private SortedDictionary<double, double> m_TickValueMap;

        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// Instance Constructor.
        /// </summary>
        public SliderMenuItem()
        {
            m_TickValueMap = new SortedDictionary<double, double>();
            InitializeComponent();
        }

        #region Attached Property Steps

        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// Xaml accessor function for Getting Steps property
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static int GetSteps(DependencyObject obj)
        {
            return (int)obj.GetValue(StepsProperty);
        }

        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// Xaml accessor function for Setting Steps property
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="value"></param>
        public static void SetSteps(DependencyObject obj, int value)
        {
            obj.SetValue(StepsProperty, value);
        }

        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// The number of steps, or tick placements between a menu item
        /// and the previous one.
        /// </summary>
        public static readonly DependencyProperty StepsProperty =
            DependencyProperty.RegisterAttached(
            "Steps",
            typeof(int),
            typeof(SliderMenuItem),
            new UIPropertyMetadata(1));

        #endregion

        #region Attached Property Value

        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// Gets or Sets the value for this slider.
        /// </summary>
        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// Xaml accessor function for Value property
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static double GetValue(DependencyObject obj)
        {
            return (double)obj.GetValue(ValueProperty);
        }

        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// Xaml accessor function for Value property
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="value"></param>
        public static void SetValue(DependencyObject obj, double value)
        {
            obj.SetValue(ValueProperty, value);
        }

        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// The real value for the slider.  
        /// </summary>
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.RegisterAttached(
            "Value",
            typeof(double),
            typeof(SliderMenuItem),
            new UIPropertyMetadata(1.0d, Value_ValueChanged));

        #endregion

        #region Attached Property Skip

        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// Skip property for sub menu items.  Allows a menu item to
        /// skip a tick mark.  Especially useful for separators.
        /// </summary>
        public static readonly DependencyProperty SkipProperty =
            DependencyProperty.RegisterAttached(
            "Skip",
            typeof(bool),
            typeof(SliderMenuItem),
            new UIPropertyMetadata(false));

        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// Xaml accessor function for Skip property.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static bool GetSkip(DependencyObject obj)
        {
            return (bool)obj.GetValue(SkipProperty);
        }

        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// Xaml accessor function for Skip property.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="value"></param>
        public static void SetSkip(DependencyObject obj, bool value)
        {
            obj.SetValue(SkipProperty, value);
        }

        #endregion

        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// Listen for change to Value property.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="e"></param>
        private static void Value_ValueChanged(DependencyObject obj,
            DependencyPropertyChangedEventArgs e)
        {
            // find appropriate tick spot, and set slider value
            SliderMenuItem item = obj as SliderMenuItem;

            if (item != null)
            {
                SetTickToValue(item, (double)e.NewValue);
            }
        }
       
        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// Listen for change to slider value.  Enables binding where
        /// SliderMenuItem is the target, and a framework element is the source.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Slider_ValueChanged(object sender,
            RoutedPropertyChangedEventArgs<double> e)
        {
            // find appropriate tick spot, and set slider value
            SetValueToTick(this, (double)e.NewValue);
        }

        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// Sets the slider thumb to the closest match after the value changes.
        /// </summary>
        /// <param name="item"></param>
        /// <param name="newValue"></param>
        private static void SetTickToValue(SliderMenuItem item, double newValue)
        {
            // find tick spot where  
            double[] ticks = new double[item.m_TickValueMap.Keys.Count];
            item.m_TickValueMap.Keys.CopyTo(ticks, 0);

            // Find exact match
            if (item.m_TickValueMap.ContainsValue(newValue))
            {
                foreach (double tick in item.m_TickValueMap.Keys)
                {
                    if (item.m_TickValueMap[tick] == newValue)
                    {
                        item.m_Slider.Value = tick;
                        return;
                    }
                }
            }

            // Find closest match
            for (int i = 1; i < item.m_TickValueMap.Count; i++)
            {

                double lowTick = ticks[i - 1];
                double highTick = ticks[i];

                double lowValue = item.m_TickValueMap[lowTick];
                double highValue = item.m_TickValueMap[highTick];

                //double newValue = (double)e.NewValue;

                if (newValue > lowValue &&
                    newValue < highValue)
                {
                    double valueScale = highValue - lowValue;
                    double tickScale = highTick - lowTick;

                    // set slider to closest tick match
                    double newTick = (newValue - lowValue) / (valueScale) * tickScale + lowTick;

                    item.m_Slider.Value = newTick;
                }
            }
        }

        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// After the slider value has changed, update the Value property to
        /// hold the scaled value.
        /// </summary>
        private static void SetValueToTick(SliderMenuItem item, double tickValue)
        {
            if (item.m_TickValueMap.ContainsKey(tickValue))
            {
                item.Value = item.m_TickValueMap[tickValue];
                return;
            }

            double[] keys = new double[item.m_TickValueMap.Keys.Count];
            item.m_TickValueMap.Keys.CopyTo(keys, 0);

            int index = Array.BinarySearch<double>(keys, tickValue);

            Debug.Assert(index < 0, "What? How come I didn't find the key already?");

            index = ~index;

            Debug.Assert(index < item.Items.Count, "How did tick value go above 1000?");
            Debug.Assert(index != 0, "Insert location was before element 0.");

            double lowTick = keys[index - 1];
            double highTick = keys[index];

            double lowValue = item.m_TickValueMap[lowTick];
            double highValue = item.m_TickValueMap[highTick];

            double valueScale = highValue - lowValue;
            double sourceScale = highTick - lowTick;

            double newValue = (tickValue - lowTick) * valueScale / sourceScale + lowValue;
            item.Value = newValue;
        }

        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// After template is applied, save reference to slider object.
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            this.m_Slider = this.Template.FindName("PART_Slider", this) as Slider;

            if (m_Slider == null)
                throw new InvalidOperationException("Control template is missing part Slider_PART");

            m_Slider.ValueChanged += Slider_ValueChanged;
        }
 
        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// Arrange pass.  Call base method to figure out menu item placement,
        /// then place tick marks at the centers of the menu items.
        /// </summary>
        /// <param name="arrangeBounds"></param>
        /// <returns></returns>
        protected override Size ArrangeOverride(Size arrangeBounds)
        {
            Size returnSize = base.ArrangeOverride(arrangeBounds);

            FrameworkElement topElement = null;
            FrameworkElement bottomElement = null;

            for (int i = 0; i < Items.Count; i++)
            {
                FrameworkElement elem = Items[i] as FrameworkElement;

                Debug.Assert(elem != null, "Added an object that wasn't a FrameworkElement??");

                // Find the bottom element.  It must have a value greater or equal to the
                // top element
                if (topElement != null)
                {
                    if ((double)elem.GetValue(SliderMenuItem.ValueProperty) >=
                        (double)topElement.GetValue(SliderMenuItem.ValueProperty))
                    {
                        bottomElement = elem;
                    }
                }

                // Move along.  Nothing to see here.
                if ((bool)(elem.GetValue(SliderMenuItem.SkipProperty)))
                    continue;

                // set the first element
                if (topElement == null)
                    topElement = elem;
            }
           
            // Single element.  Not much of a slider, but don't crash
            if (bottomElement == null && topElement != null)
                bottomElement = topElement;

            // No elements.  Nothing to do.
            if (bottomElement == null && topElement == null)
                return returnSize;

            // Calculate top, bottom margins.
            // This margin enables the thumb stop at 0 and 100 to line up with
            // the center of the top and bottom menu items.
            Rect bound = LayoutInformation.GetLayoutSlot(topElement);

            double topMargin = bound.Top + ThumbHeight / 2;
            double pointZero = bound.Top + bound.Height / 2.0;

            bound = LayoutInformation.GetLayoutSlot(bottomElement);
           
            double bottomMargin = returnSize.Height - bound.Bottom + ThumbHeight / 2.0d;
            double pointOneHundred = bound.Top + bound.Height / 2.0d;

            // Set the margin.
            m_Slider.Margin = new Thickness(0, topMargin, 0, bottomMargin);


            for (int i = 0; i < Items.Count; i++)
            {
                FrameworkElement elem = Items[i] as FrameworkElement;

                if (elem is MenuItem)
                    ((MenuItem)elem).Click += new RoutedEventHandler(SliderMenuItem_Click);

                // Move along.  Nothing to see here.
                if ((bool)(elem.GetValue(SliderMenuItem.SkipProperty)))
                    continue;

                // Grab the coordinates of the child menu item
                bound = LayoutInformation.GetLayoutSlot(elem);

                // Get the number of steps, or tick spots between this child menu item
                //  and the previous one.
                int steps = (int)elem.GetValue(SliderMenuItem.StepsProperty);

                // A value of 0 for Steps is like setting Skip = true
                if (steps < 1)
                    continue;

                // Calculate tick spot.
                double thisTickSpot = 1000.0d * (bound.Top - pointZero + bound.Height / 2.0d)
                    / (pointOneHundred - pointZero);

                // Calculate continuous tick spots.  Only allow continuous after the first element.
                if (m_Slider.Ticks.Count > 0)
                {
                    double lastTickSpot = m_Slider.Ticks[m_Slider.Ticks.Count - 1];
                    double division = (thisTickSpot - lastTickSpot) / steps;

                    for (int current_step = 1; current_step < steps; current_step++)
                    {
                        double intermediateTickSpot = lastTickSpot + current_step * division;
                        m_Slider.Ticks.Add(intermediateTickSpot);
                    }
                }

                m_Slider.Ticks.Add(thisTickSpot);
                double sliderValue = (double)elem.GetValue(SliderMenuItem.ValueProperty);
                m_TickValueMap[thisTickSpot] = sliderValue;

            }

            // At end of arrange pass, set the tick to the inital value
            SetTickToValue(this, Value);

            return returnSize;
        }

        /// §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
        /// <summary>
        /// A child menu item was clicked.  Set the value automatically.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SliderMenuItem_Click(object sender, RoutedEventArgs e)
        {
            this.Value = (double)((DependencyObject)sender).GetValue(SliderMenuItem.ValueProperty);
        }
    }
}
 

Re: How make it?

PostPosted: Tue Nov 12, 2019 12:51 pm
by Silvio.Falconi
for now I resolve in this mode:

Image
the user can use the percentual on Total or make a descount on days
it is beautifull but not professonal work

Re: How make it?

PostPosted: Tue Nov 12, 2019 1:04 pm
by cnavarro
Dear Silvio
Currently it is not possible, but it is not impossible
For some time I was studying that possibility, but for lack of time I left it unfinished.
I hope to be able to return to the subject and get what you propose. It is not simple because although the item has hWnd it is not considered as a container of controls. We'll see