How enable/disable a wxRadioBox item using a mouse left double click - windows

Under wxWidgets 2.8 I want to enable or disable a wxRadioBox item using a mouse left double click on the label which identify the item.
To this end I plan to use the GetItemFromPoint to identify the item.
The problem is that I cant't able to capture the mouse event when do a double click over the wxRadioBox, neither on the parent panel, nor using a derived class of wxRadioBox.
A sample code
in .h file
class PrinterRadioBox: public wxRadioBox
{
public:
PrinterRadioBox(wxWindow* parent, wxWindowID id, const wxString& label, const wxPoint& point, const wxSize& size, int n, const wxString choices[], int majorDimension, long style, const wxValidator& validator, const wxString& name)
: wxRadioBox(parent,id, label, point, size, n, choices, majorDimension, style, validator, name)
{
}
PrinterRadioBox(wxWindow* parent, wxWindowID id, const wxString& label, const wxPoint& point, const wxSize& size, const wxArrayString& choices, int majorDimension = 0, long style = wxRA_SPECIFY_COLS, const wxValidator& validator = wxDefaultValidator, const wxString& name = "radioBox")
: wxRadioBox(parent, id, label, point, size, choices, majorDimension, style, validator, name)
{
}
void OnLeftDClick(wxMouseEvent& event);
private:
DECLARE_NO_COPY_CLASS(PrinterRadioBox)
DECLARE_EVENT_TABLE()
};
in .cpp file
BEGIN_EVENT_TABLE(PrinterRadioBox, wxRadioBox)
EVT_LEFT_DCLICK(PrinterRadioBox::OnLeftDClick)
END_EVENT_TABLE()
void PrinterRadioBox::OnLeftDClick(wxMouseEvent& event)
{
wxMessageBox("here radio box");
event.Skip();
}
How can I enable or disable a single item (element) of a wxRadioBox by selecting it with a double click?

At least in wxMSW, wxRadioBox is a composite native control consisting of a box and the buttons inside it and you're going to have problems catching events from those. If you really need to do this, consider using individual wxRadioButtons instead.
I also believe wxRadioBox implementation has changed since 2.8 (hard to remember all the details for 10+ year old version...), so you really should switch to a more recent wx version.

Related

Xamarin.Forms: Scroll effect with collapsing sections of the screen

I'm looking for help on how to do this effect:
On a page is a ListView that is 3cm from the top of the page, below a 3cm tall logo. When the user scrolls up the list view, the entire list view scrolls up to take up the 1/2 the space of the logo. Reverse when going down. So basically the Logo gets it's size allocation reduced. Both the logo and the listview can be in a scroll view, but how do I resize the logo
I'm posting the answer you placed on another site in case others searching for the solution only come across this article.
private const int ScrollMinLimit = 0;
private const int ScrollMaxLimit = 190;
private void ScrollView_Scrolled(object sender, ScrolledEventArgs e)
{
var val = MathHelper.ReMap(e.ScrollY, ScrollMinLimit, ScrollMaxLimit, 1, 0);
this.infoPanel.Scale = val;
this.infoPanel.Opacity = val;
}
and
public static class MathHelper
{
public static double ReMap(double oldValue, double oldMin, double oldMax, double newMin, double newMax)
{
return (((oldValue - oldMin) / (oldMax - oldMin)) * (newMax - newMin)) + newMin;
}
}

Forcing a combobox to "dropdown" above instead of below

When you click on the "dropdown" button of a combobox, the dropped down listbox appears below the combobox, unless there is not enough space below, in which case the listbox appears above.
Now I wonder if there is a possibility to force the lisbox to appear above the combobox, even if there is enough space below.
Illustration
When I click on the combo box, I'd like the "drop down" list box appear always above as on the left screen copy.
Everything is possible, and you don't need to implement the control "from scratch".
First, you can subclass the ListBox part of your ComboBox to get complete control over it, as explained in MSDN. You can create a class, derived from CListBox, using the Class Wizard. You only need to implement WM_WINPOSITIONCHANGING handler in it:
void CTopListBox::OnWindowPosChanging(WINDOWPOS* lpwndpos)
{
CListBox::OnWindowPosChanging(lpwndpos);
if ((lpwndpos->flags & SWP_NOMOVE) == 0)
{
lpwndpos->y -= lpwndpos->cy + 30;
}
}
Here, for simplicity, I am moving the box up by the (heights+30). You can get the height of your ComboBox instead of my 30.
Then you declare a member variable in your dialog class:
CTopListBox m_listbox;
and subclass it like that:
HBRUSH CMFCDlgDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
if (nCtlColor == CTLCOLOR_LISTBOX)
{
if (m_listbox.GetSafeHwnd() == NULL)
{
m_listbox.SubclassWindow(pWnd->GetSafeHwnd());
CRect r;
m_listbox.GetWindowRect(r);
m_listbox.MoveWindow(r);
}
}
HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
return hbr;
}
Note that I am calling m_listbox.MoveWindow(r) there; it is needed because first WM_CONTROLCOLOR message for that list box comes after it is positioned, so the very first time it would drop down instead of up.
Disclaimer: this is not a very clean solution, as, if you have windows animation enabled, you'd see that the list unrolls from top to bottom.
Alternatively, you should be able to "fool" the combobox that it is too close to the bottom of the screen; then it will drop up by itself. I leave it as an exercise for the readers :)
This would be relatively easy except when combo box has "slide open" effect. If you move the dropdown listbox to the top, and the combo slides open from top-to-bottom, it would look odd. So you have to disable the animation or reverse it.
In this function I call AnimateWindow in OnWindowPosChanging, it doesn't seem to cause any problems but I am not a 100% sure about it!
class CComboBox_ListBox : public CListBox
{
public:
CWnd *comboBox;
void OnWindowPosChanging(WINDOWPOS *wndpos)
{
CListBox::OnWindowPosChanging(wndpos);
if (comboBox && wndpos->cx && wndpos->cy && !(wndpos->flags & SWP_NOMOVE))
{
CRect rc;
comboBox->GetWindowRect(&rc);
//if listbox is at the bottom...
if (wndpos->y > rc.top) {
//if there is enough room for listbox to go on top...
if (rc.top > wndpos->cy) {
wndpos->y = rc.top - wndpos->cy;
BOOL animation;
SystemParametersInfo(SPI_GETCOMBOBOXANIMATION, 0, &animation, 0);
//if combobox slides open...
if (animation) {
//we have to set the x coordinate otherwise listbox
//is in the wrong place when parent window moves
SetWindowPos(0, wndpos->x, wndpos->y, 0, 0,
SWP_NOSENDCHANGING | SWP_HIDEWINDOW | SWP_NOSIZE);
AnimateWindow(100, AW_VER_NEGATIVE);
}
}
}
}
}
DECLARE_MESSAGE_MAP()
};
Usage:
COMBOBOXINFO ci = { sizeof(COMBOBOXINFO) };
comboBox.GetComboBoxInfo(&ci);
CComboBox_ListBox *listBox = new CComboBox_ListBox;
listBox->comboBox = &comboBox;
listBox->SubclassWindow(ci.hwndList);
Also you can use SetMinVisibleItems to reduce the listbox height and make sure the dropdown list fits on top.

IUP, mouse events on matrix

I have basic confusion in understanding of IUP events system.
Now I am talking about matrix.
This is how it is created:
Ihandle *create_mat(void)
{
mat = IupMatrix(NULL);
IupSetAttribute(mat, "READONLY", "YES");
IupSetCallback(mat, "CLICK_CB", (Icallback)click);
IupSetCallback(mat, "BUTTON_CB", (Icallback)button);
return mat;
}
Here are callbacks:
int click(Ihandle *mat, int lin, int col)
{
char* value = IupMatGetAttribute(mat, "", lin, col);
if (!value) value = "NULL";
printf("click_cb(%d, %d)\n", lin, col);
return IUP_DEFAULT;
}
int button(Ihandle *mat, int button, int pressed, int x, int y, char* status)
{
printf("button %d, %d, %d, %d %s\n", button, pressed, x, y, status);
return IUP_DEFAULT;
}
Problem is in that I need both callbacks active but in showed situation CLICK event isn't fired.
If I disable BUTTON_CB then CLICK event is fired. But I need both, for click, left button doubleclick, right button release etc...
Is this normal behavior that BUTTON_CB excludes CLICK_CB or I do something wrong?
Actually, how would I get "lin" and "col" from inside BUTTON_CB or WHEEL_CB handler of matrix if CLICK_CB, ENTERITEM_CB and LEAVEITEM_CB which gives lin and col is not available (not fired in described situation)?
And more, how would I get "active control" (name, type of control with focus) from event handlers used on form's level?
Is this normal behavior that BUTTON_CB excludes CLICK_CB or I do something wrong?
Yes, it is. Because the BUTTON_CB is a IupCanvas callback and CLICK_CB is a IupMatrix callback. Remeber that IupMatrix inherits from IupCanvas. So internally IupMatrix is using the BUTTON_CB callback to implement several features.
So in this case what you have to do is to save the previous callback before assigning a new one, and call the old one from inside your own. Something like this:
old_callback = IupGetCallback(mat, "BUTTON_CB");
IupSetCallback(mat, "BUTTON_CB", new_callback);
int new_callback(...)
{
return old_callback(...)
}
Actually, how would I get "lin" and "col" from inside BUTTON_CB or WHEEL_CB handler of matrix if CLICK_CB, ENTERITEM_CB and LEAVEITEM_CB which gives lin and col is not available (not fired in described situation)?
Use the function pos = IupConvertXYToPos(mat, x, y) where pos=lin*numcol + col. To compute lin and col is quite simple considering they are integer values.
And more, how would I get "active control" (name, type of control with focus) from event handlers used on form's level?
I don't fully undestood your question. But I think that IupGetFocus and IupGetClassName could be the functions you want.
I will answer to my own question by using Antonio's advices so other people interesting for IUP can have benefit from those posts.
If I understand well, what is not likely, here is how I make BUTTON_CB handler for my matrix:
int button(Ihandle *mat, int button, int pressed, int x, int y, char* status)
{
//actually 'name' is Ihandle
//and class name is a 'type'
//in compare with other toolkits
char* name = IupGetClassName(mat);
//so since we have handle already
//we can't be here if we are not in concrete matrix
//and this comparision is not needed
if (strncmp(name, "matrix", sizeof(name)) == 0)
{
//if left mouse button is down
if (button == IUP_BUTTON1 && pressed == 1)
{
//my calculation is not 100% correct
//but good enough for this sample
int pos = IupConvertXYToPos(mat, x, y);
_line = pos/numcol;
_col = pos%numcol;
//if is doubleclick
if (status[5] == 'D')
{
//press ENTER key
//and open another modal dialog
//with argument 'sel'
k_any(mat, K_CR);
printf("Doubleclick\n");
//say HANDLED for IUP
//but not matter when READONLY is "YES"
return IUP_IGNORE;
}
//calculate (public) sel
//for select a clicked line
sel = _line + from - 1;
refreshl(from, sel);
printf("Click\n");
return IUP_IGNORE;
}
}
return IUP_DEFAULT;
}
This work's as expected.
Please further suggestion if something is not OK.

BlackBerry - Custom centered cyclic HorizontalFieldManager

Trying to create a custom cyclical horizontal manager which will work as follows. It will control several field buttons where the buttons will always be positioned so that the focused button will be in the middle of the screen. As it is a cyclical manager once the focus moves to the right or left button, it will move to the center of the screen and all the buttons will move accordingly (and the last button will become the first to give it an cyclic and endless list feeling)
Any idea how to address this?
I tried doing this by implementing a custom manager which aligns the buttons according to the required layout. Each time moveFocus() is called I remove all fields (deleteAll() ) and add them again in the right order.
Unfortunately this does not work.
Using HorizontalButtonFieldSet class from KB How to - Implement advanced buttons, fields, and managers:
class CentricHManager extends HorizontalButtonFieldSet {
int focusedFieldIndex = 0;
public void focusChangeNotify(int arg0) {
super.focusChangeNotify(arg0);
int focusedFieldIndexNew = getFieldWithFocusIndex();
if (focusedFieldIndexNew != focusedFieldIndex) {
if (focusedFieldIndexNew - focusedFieldIndex > 0)
switchField(0, getFieldCount() - 1);
else
switchField(getFieldCount() - 1, 0);
}
}
private void switchField(int prevIndex, int newIndex) {
Field field = getField(prevIndex);
delete(field);
insert(field, newIndex);
}
public void add(Field field) {
super.add(field);
focusedFieldIndex = getFieldCount() / 2;
setFieldWithFocus(getField(focusedFieldIndex));
}
}

How do I limit mouse pointer movement in wxWidgets?

Is there a way to limit mouse pointer movement to a specific area in wxWidgets? I know there is an API function ClipCursor() in Windows, but is there a method in wxWidgets for all platforms?
No. There is no such function in wx by all i know. Start up a timer (say 50ms) checking the global mouse position. If the mouse is outside the region, then set it into again.
If you want to restrict the mouse for some certain reason, for example to make some sort of game, then you can capture the mouse (see wxWindow::CaptureMouse). You will get mouse events even if the pointer is outside your window. Then you could react to mouse-motion events and do the check for the position there, without a timer. Downside of this is that the mouse won't be able to be used somewhere else for other programs since they won't receive events.
wxWidgets manual states that OSX guidelines forbid the programs to set the mouse pointer to a certain position programmatically. That might contribute to the reason there is not much support for such stuff in wx, especially since wx tries really hard to be compatible to everything possible.
Small sample. Click on the button to restrict the mouse to area 0,0,100,100. Click somewhere to release it.
#include <wx/wx.h>
namespace sample {
class MyWin : public wxFrame {
public:
MyWin()
:wxFrame(0, wxID_ANY, wxT("haha title")) {
mRestricted = wxRect(0, 0, 100, 100);
mLast = mRestricted.GetTopLeft();
wxButton * button = new wxButton(this, wxID_ANY, wxT("click this"));
}
private:
void OnClicked(wxCommandEvent& event) {
if(!HasCapture()) {
CaptureMouse();
CheckPosition();
}
}
void OnMotion(wxMouseEvent& event) {
CheckPosition();
}
void OnLeft(wxMouseEvent& event) {
if(HasCapture())
ReleaseMouse();
}
void CheckPosition() {
wxPoint pos = wxGetMousePosition();
if(!mRestricted.Contains(pos)) {
pos = ScreenToClient(mLast);
WarpPointer(pos.x, pos.y);
} else {
mLast = pos;
}
}
wxRect mRestricted;
wxPoint mLast;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(MyWin, wxFrame)
EVT_BUTTON(wxID_ANY, MyWin::OnClicked)
EVT_MOTION(MyWin::OnMotion)
EVT_LEFT_DOWN(MyWin::OnLeft)
END_EVENT_TABLE()
class MyApp : public wxApp {
virtual bool OnInit() {
MyWin * win = new MyWin;
win -> Show();
SetTopWindow(win);
return true;
}
};
} /* sample:: */
IMPLEMENT_APP(sample::MyApp)

Resources