locked
How to create a logarithmic slider

    Question

  • I'm creating a windows store app that does audio synthesis, and I would like to create a logarithmic slider control (the value is a log function of the position of the thumb, similar to a log taper potentiometer). I'd like to inherit as much as possible from the default one so it responds to themes, looks the same, and doesn't involve much reimplementation.

    So far, I've got this

    LogSlider.h:

    //
    // LogSlider.h
    // Declaration of the LogSlider class.
    //
    
    #pragma once
    
    namespace Synth
    {
    	public ref class LogSlider sealed : public Windows::UI::Xaml::Controls::Slider
    	{
    	public:
    		LogSlider();
    		void OnValueChanged(double oldVal, double newVal) override;
    	};
    }

    LogSlider.cpp:

    LogSlider::LogSlider()
    {
    	DefaultStyleKey = "Synth.LogSlider";
    }
    
    void
    LogSlider::OnValueChanged(double oldVal, double newVal) {
    	double normNewVal = (newVal - Minimum) / (Maximum - Minimum);
    	Slider::OnValueChanged(oldVal, (Maximum - Minimum) * log(normNewVal) + Minimum);
    }

    But when I try to instantiate one in my app (in MainPage.xaml), like this:

    <local:LogSliderx:Name="LogSliderFrequency"Grid.Row="0"Grid.Column="3"Orientation="Horizontal"Maximum="20000"/>

    It compiles and runs fine, but where I would expect my LogSlider to be, there's a blank spot. It doesn't show up in designer view either (rather, it shows up as something that appears to have no width or height). I have a regular slider immediately above it with a  different name  and the exact same other parameters, and it works fine.

    Thanks for any help!


    Tuesday, December 10, 2013 6:33 AM

All replies

  • Hi Magus,

    Please post implementation questions in the appropriate forum for the language you are using. The UI Design forum is for discussing what the UI should look like, not how to implement it.

    What does the style you have created for your LogSlider look like?

    --Rob1

    Tuesday, December 10, 2013 7:57 AM
    Owner
  • The style is whatever default one comes with the new item template. I think the problem I'm having is that I haven't defined a ControlTemplate (apparently they don't inherit along with everything else) but I don't really want to design an entirely new slider control when the standard XAML library comes with a perfectly good one.

    So I guess the question is: Is there a way to import/cross-reference/{SomethingResource } the ControlTemplate from a Slider? Or at least somewhere I can paste the builtin slider code from without violating licenses?

    Here's my Generic.xaml (is that what you mean by style?):

    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:Synth">
    
        <Style TargetType="local:LogSlider">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="local:LogSlider">
                        <Border
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>

    Tuesday, December 10, 2013 8:19 AM
  • Hi Magus,

    You are telling the LogSlider to default to the LogSlider style when you set the DefaultStyleKey property in your constructor. If you want your control to use the original Slider style then remove that line.

    To make a simple override of the control you don't need to use the full template control item. You can just create a new class which inherits from the original.

    --Rob

    • Marked as answer by MagusOTB Sunday, December 15, 2013 12:05 AM
    • Unmarked as answer by MagusOTB Monday, December 16, 2013 1:05 AM
    Thursday, December 12, 2013 2:27 AM
    Owner
  • So I did that, and now it shows up, but I'm having some trouble figuring out what I should be overriding to get the behavior I want. I figured I could override OnValueChanged, map the value to a log function, and call the superclass version with the mapped value, but that doesn't seem to be working (it has no effect). I also tried setting Value directly from within said handler, but that seemed to result in some weird recursion (apparently not infinite), which mapped everything to 1, looking at debug output, the handler was being called multiple times with the results of previous invocations.

    Sorry for my ignorance, I'm sort of a n00b at Windows/C++

    inline void LogSlider::OnValueChanged(double oldVal, double newVal) { double range = Maximum - Minimum; double base = exp(log(range) / range); double mappedVal = pow(base, newVal - Minimum); OutputDebugString( (L"\nRange: " + range + "\nbase: " + base + "\nmappedVal: " + mappedVal + "\nnewVal: " + newVal + " -> " + (mappedVal + Minimum))->Data()); //Value = mappedVal + Minimum; Slider::OnValueChanged(oldVal, mappedVal + Minimum);

    }

    Sunday, December 15, 2013 2:42 AM