Knob Control

If you have a cool piece of software to share, but you are not hosting it officially yet, please dump it in here. If you have code snippets that are useful, please donate!
Post Reply
pkoning
In need of some credit
In need of some credit
Posts: 6
Joined: Fri Jul 22, 2005 7:55 pm

Post by pkoning »

Here's a (fairly crude but functional) implementation, in case anyone else is interested.

paul

knob.h:

Code: Select all

/////////////////////////////////////////////////////////////////////////////
// Name:        knob.h
// Purpose:     rotary knob control
// Author:      Paul Koning
// Modified by:
// Created:     08/01/2005
// Copyright:   (c) Paul Koning
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// Define a custom control that looks like a rotary knob
class wxKnob : public wxControl
{
public:
    wxKnob () : wxControl () { }
    wxKnob (wxWindow* parent, wxWindowID id, int value,
            int minValue, int maxValue,
            unsigned int minAngle = 240, unsigned int range = 300,
            const wxPoint &pos = wxDefaultPosition, 
            const wxSize &size = wxDefaultSize, 
            long style = 0,
            const wxValidator &validator = wxDefaultValidator,
            const wxString &name = wxT ("knob"))
    {
        Create (parent, id, value, minValue, maxValue,
                minAngle, range, pos, size, style, validator, name );
    }
    void Create (wxWindow* parent, wxWindowID id, int value,
                 int minValue, int maxValue,
                 unsigned int minAngle = 240, unsigned int range = 300,
                 const wxPoint &pos = wxDefaultPosition, 
                 const wxSize &size = wxSize (30, 30), 
                 long style = 0,
                 const wxValidator &validator = wxDefaultValidator,
                 const wxString &name = wxT ("knob"));

    // retrieve/change the range
    void SetRange (int minValue, int maxValue);
    int GetMin() const { return m_min; }
    int GetMax() const { return m_max; }
    void SetMin (int minValue) { SetRange( minValue , GetMax() ) ; }
    void SetMax (int maxValue) { SetRange( GetMin() , maxValue ) ; }
    unsigned int GetMinAngle() const { return (m_maxAngle - m_range) % 360; }
    int GetMaxAngle() const { return m_maxAngle; }
    int GetValue () const { return m_setting; }
    int SetValue (int value);

private:
    int m_min;
    int m_max;
    int m_setting;
    unsigned int m_maxAngle;
    unsigned int m_range;

    void GetCenter (int &x, int &y) const;
    void OnPaint(wxPaintEvent &event);
    void OnMouse (wxMouseEvent &event);

    DECLARE_EVENT_TABLE()
};
knob.cpp:

Code: Select all

/////////////////////////////////////////////////////////////////////////////
// Name:        knob.cpp
// Purpose:     rotary knob control
// Author:      Paul Koning
// Modified by:
// Created:     08/01/2005
// Copyright:   (c) Paul Koning
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
    #pragma implementation "knob.h"
#endif

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#ifndef WX_PRECOMP
    #include "wx/control.h"
    #include "wx/settings.h"
    #include "wx/dc.h"
    #include "wx/dcclient.h"
#endif // WX_PRECOMP

#include "knob.h"
#include <math.h>

#define PI 3.14159265358969323846
#define irnd(x) (int (round (x)))

// ----------------------------------------------------------------------------
// the wxKnob class
// ----------------------------------------------------------------------------
BEGIN_EVENT_TABLE(wxKnob,wxControl)
    EVT_PAINT       (wxKnob::OnPaint)
    EVT_LEFT_DOWN   (wxKnob::OnMouse)
    EVT_LEFT_UP     (wxKnob::OnMouse)
    EVT_MOTION      (wxKnob::OnMouse)
END_EVENT_TABLE()

// Constructor
void wxKnob::Create (wxWindow* parent, wxWindowID id, int value,
                     int minValue, int maxValue,
                     unsigned int minAngle, unsigned int range,
                     const wxPoint &pos, 
                     const wxSize &size, 
                     long style,
                     const wxValidator &validator,
                     const wxString &name)
{
    wxControl::Create (parent, id);
    SetInitialBestSize (size);
//    SetClientSize (size);
    
    m_min = minValue;
    m_max = maxValue;
    range %= 360;
    minAngle %= 360;
    m_maxAngle = (minAngle + 360 - range) % 360;
    
    m_range = range;
    SetValue (value);
}

void wxKnob::SetRange (int minValue, int maxValue)
{
    if (minValue < maxValue)
    {
        m_min = minValue;
        m_max = maxValue;
        SetValue (m_setting);
    }
}
    
int wxKnob::SetValue (int value)
{
    if (value < m_min)
        value = m_min;
    if (value > m_max)
        value = m_max;
    
    if (value != m_setting)
    {
        m_setting = value;
        Refresh ();
        Update ();
        
    }
}

void wxKnob::OnPaint(wxPaintEvent& WXUNUSED(event))
{
    int sizeX, sizeY;
    double theta;
    double dx, dy;
    int cx, cy;
    int r, r2;
    wxSize s = GetSize ();
    
    theta = (PI / 180.) * (m_maxAngle +
                           (((double) m_max - m_setting) / (m_max - m_min))
                           * m_range);
    dx = cos (theta);
    dy = -sin (theta);      // - because of upside down coordinates
    
    wxPaintDC dc(this);

    GetCenter (cx, cy);
    r = irnd (((s.x < s.y) ? s.x : s.y) * .48);
    r2 = irnd (r * .6);
    
    dc.BeginDrawing();

    dc.SetPen (*wxBLACK_PEN);
    dc.DrawCircle (cx, cy, r);
    dc.DrawLine (cx + irnd (r * dx), cy + irnd (r * dy),
                 cx + irnd (r2 * dx), cy + irnd (r2 * dy));
    
    dc.EndDrawing();

}

void wxKnob::OnMouse (wxMouseEvent &event)
{
    int cx, cy;
    double dx, dy, theta, dt;
    int newval;
    wxEventType scrollEvent = wxEVT_NULL ;
    
    if (event.Moving ())
    {
        event.Skip ();
        return;
    }
    
    GetCenter (cx, cy);
    dx = event.m_x - cx;
    dy = cy - event.m_y;
    if (dx == 0. && dy == 0.)
        return;
    
    theta = atan2 (dy, dx) * 180. / PI;
    if (theta < 0.)
        theta += 360.;
    
    dt = theta - m_maxAngle;
    if (dt < 0.)
        dt += 360;
    if (dt > m_range)
        return;
    newval = int (m_max - (dt / m_range) * (m_max - m_min));

    SetValue (newval);
    if (event.Dragging () || event.ButtonUp ())
    {
        if (event.ButtonUp ())
            scrollEvent = wxEVT_SCROLL_THUMBRELEASE;
        else
            scrollEvent = wxEVT_SCROLL_THUMBTRACK;
            
        wxScrollEvent event (scrollEvent, m_windowId);
        event.SetPosition (newval);
        event.SetEventObject (this);
        GetEventHandler()->ProcessEvent (event);

        wxCommandEvent cevent (wxEVT_COMMAND_SLIDER_UPDATED, m_windowId);
        cevent.SetInt (newval);
        cevent.SetEventObject (this);
        GetEventHandler()->ProcessEvent (cevent);
    }
}

void wxKnob::GetCenter (int &x, int &y) const
{
    wxSize s = GetSize ();
    x = s.x / 2;
    y = s.y / 2;
}
upCASE
Moderator
Moderator
Posts: 3176
Joined: Mon Aug 30, 2004 6:55 am
Location: Germany, Cologne

Post by upCASE »

Hi!
Thanks for contributing this. May I suggest you post it at the "code dump" section of this forum and consider posting it on http://wxcode.sourceforge.net/index.php?
OS: OpenSuSE, Ubuntu, Win XP Pro
wx: svn
Compiler: gcc 4.5.1, VC 2008, eVC 4

"If it was hard to write it should be hard to read..." - the unknown coder
"Try not! Do. Or do not. There is no try." - Yoda
jsoldi
Experienced Solver
Experienced Solver
Posts: 73
Joined: Thu Feb 02, 2006 6:03 am

Post by jsoldi »

Hi I tryed to compile your class but I got this error:

1>.\Knob.cpp(113) : error C3861: 'round': identifier not found


What is "round"?
Jorg
Moderator
Moderator
Posts: 3971
Joined: Fri Aug 27, 2004 9:38 pm
Location: Delft, Netherlands
Contact:

Post by Jorg »

It is declared in math.h .. Maybe you have to explicity include it in your source. It might be that on some platforms it was already defined.

- Jorgen
Forensic Software Engineer
Netherlands Forensic Insitute
http://english.forensischinstituut.nl/
-------------------------------------
Jorg's WasteBucket
http://www.xs4all.nl/~jorgb/wb
lowjoel
Part Of The Furniture
Part Of The Furniture
Posts: 1511
Joined: Sun Jun 19, 2005 11:37 am
Location: Singapore
Contact:

Post by lowjoel »

I don't remember having a round(). In <cmath> IIRC there's only floor() and ceil() but no round...

Joel
MacLanthan
In need of some credit
In need of some credit
Posts: 1
Joined: Sun Feb 25, 2007 7:25 pm

Post by MacLanthan »

In

Code: Select all

int wxKnob::SetValue (int value)
{
    if (value < m_min)
        value = m_min;
    if (value > m_max)
        value = m_max;
   
    if (value != m_setting)
    {
        m_setting = value;
        Refresh ();
        Update ();
       
    }
}
a return value of type integer ist declared, but no return value is given.
Troels
Experienced Solver
Experienced Solver
Posts: 79
Joined: Fri Jan 07, 2005 12:02 pm
Location: Denmark

Post by Troels »

wxRound() should do the job.

/Troels
Post Reply