Process only tiled event and not maximize event - c++

I'm building a very basic calculator program using GTKMM
Basic Calculator screenshot
The layout is in landscape mode (buttons and display label in horizontal orientation) by design
I want to orient those two to portrait mode (ie., in vertical) when the user snaps/tiles the window to the right or left
Below is a sample code I used:
bool
BasicCalculator::on_calculator_window_state_changed(
GdkEventWindowState *window_state_event,
Gtk::Box *box)
{
if (
window_state_event->new_window_state &
(Gdk::WINDOW_STATE_RIGHT_TILED | Gdk::WINDOW_STATE_LEFT_TILED)
)
box->set_orientation(Gtk::ORIENTATION_VERTICAL);
else
box->set_orientation(Gtk::ORIENTATION_HORIZONTAL);
return true;
}
Window tiled left and right
Window maximized
The code works but my window orients vertically when maximized which is not my intention. I want it to be in horizontal orientation
How do I process only the tiled event and not the maximize event?
PS: My project repo in case you want to build & test

After hacking around a bit with the GdkEventWindowState enums, I figured I can compare against the tiled state with the window maximized state together
ie., make sure to switch orientation to vertical only if the window is tiled and not maximized
Because the code
...
if (
window_state_event->new_window_state &
(Gdk::WINDOW_STATE_RIGHT_TILED | Gdk::WINDOW_STATE_LEFT_TILED)
)
...
returns TRUE not just for the tiled state but also for maximized state also
Below is the improved code that works:
bool
BasicCalculator::on_calculator_window_state_changed(
GdkEventWindowState *window_state_event,
Gtk::Box *box)
{
bool is_window_tiled = window_state_event->new_window_state &
(Gdk::WINDOW_STATE_RIGHT_TILED | Gdk::WINDOW_STATE_LEFT_TILED);
bool is_window_maximized = window_state_event->new_window_state &
Gdk::WINDOW_STATE_MAXIMIZED;
if (is_window_tiled && !is_window_maximized)
box->set_orientation(Gtk::ORIENTATION_VERTICAL);
else
box->set_orientation(Gtk::ORIENTATION_HORIZONTAL);
return true;
}
Now the window keeps its default horizontal orientation even if maximized :)

Related

Jittery movement of QScrollArea from custom touchscreen driver

So a few years ago, I wrote a custom touchscreen driver specifically for a particular application which ran on a Scientific Linux 6.4 (CentOS 6 based) OS, which did not have native touch support, but the kernel supported touch events, so I was able to directly read the raw data from the touchscreen in /dev/input/event* and read the event data to generate mouse events with Qt to control the application to mimic a multi-touch touchscreen. More recently, we've finally migrated to RedHat 8.4, but I had to disable the native touch driver, because as far as I know, the native Qt touch events didn't allow the same degree of control over the application that my driver did.
Recently during a trial, a technician reported that when using the touchscreen to manipulate one of the application's image display areas, the movement was very "jittery". The image display area is simply a QScrollArea with a QImage inside, and hidden scroll bars. The way it works is that on a mouseMoveEvent, it manipulates the scrollbars according to the delta value on the mouse event.
void PanArea::mouseMoveEvent(QMouseEvent* e)
{
SafeStr str;
if (m_pw)
{
if (m_disable_panning == false &&
e->buttons().testFlag(Qt::RightButton))
{
QPoint delta = e->pos() - m_last_pos;
horizontalScrollBar()->setValue(horizontalScrollBar()->value() -
delta.x());
verticalScrollBar()->setValue(verticalScrollBar()->value() -
delta.y());
m_last_pos = e->pos();
emit signalScrollPositionChanged(getScrollPosition());
// This force update has been added because
// when fast panning cause black to appear within the image
// because some pan widget updates were being skipped.
// Performance seems acceptable with this here.
m_pw->update();
}
else if (...)
{
// irrelevant code removed to save space
}
}
}
This works fine when simply right-click dragging on the scroll area. And then here is the relevant function that dispatches the mouse press and mouse move events from the touchscreen driver:
void InputHandler::panStart(TouchPoint* tp, QWidget* widget)
{
QPoint pos(tp->cx(), tp->cy());
QWidget* target = widget;
if (target == NULL) target = QApplication::widgetAt(pos);
if (target != NULL)
{
QPoint local = target->mapFromGlobal(pos);
QMouseEvent* press =
new QMouseEvent(QEvent::MouseButtonPress, local, pos,
Qt::RightButton, Qt::RightButton, Qt::NoModifier);
QApplication::postEvent(widget, press);
}
}
void InputHandler::panMove(TouchPoint* tp, QWidget* widget)
{
QPoint pos(tp->cx(), tp->cy());
QWidget* target = widget;
if (target == NULL) target = QApplication::widgetAt(pos);
if (target != NULL)
{
QPoint local = target->mapFromGlobal(pos);
QMouseEvent* move =
new QMouseEvent(QEvent::MouseMove, local, pos, Qt::NoButton,
Qt::RightButton, Qt::NoModifier);
QApplication::postEvent(widget, move);
}
}
When I touch and drag on the widget, it DOES move, but it jumps all over the place as if I were rapidly dragging it in random directions.
Is there some caveat of how Qt5 mouse events work that could explain this behavior? Or something to do with the way the widget is moving the image around?

How to set Direct Draw clipper according to window's client area position relative to the screen

I'm adding Direct Draw rendering option to my 2D Graphics Engine.
When setting the Direct Draw Clipper on a non fullscreen application clipper clips the client area with an offset if the Window's client area top left position is not on the 0,0 of the screen.
Here is my clipper setup code :
LPDIRECTDRAWCLIPPER directDrawClipper = nullptr;
if (!FAILED(mDirectDraw->CreateClipper(0, &directDrawClipper, NULL))) {
if (!FAILED(directDrawClipper->SetHWnd(0, App->getWindow()->getHandle()))) {
if (!FAILED(mDirectDrawFrontBuffer->SetClipper(directDrawClipper))) {
if (!FAILED(mDirectDrawBackBuffer->SetClipper(directDrawClipper))) {
return true; //all good
} else {
throw Error::Exception(L"DirectDraw arka görüntü bellek tamponu kesicisi kurulamadı",
L"Renderer Kurulum Hatası");
}
} else {
throw Error::Exception(L"DirectDraw ana görüntü bellek tamponu kesicisi kurulamadı",
L"Renderer Kurulum Hatası");
}
} else {
throw Error::Exception(L"DirectDraw kesicisi pencereye kurulamadı",
L"Renderer Kurulum Hatası");
}
} else {
throw Error::Exception(L"DirectDraw kesicisi kurulamadı",
L"Renderer Kurulum Hatası");
}
And here is the screenshot :
the size of the white areas are the distance of client area to the screen upper left corner.
Moving the window to upper left corner of the screen before setting the clipper and moving it back to original position doesn't help.
Thanks in advance.
For the curious I solved the problem with a hack.
Before setting the clipper move the window to a position which the client area of the window will be on 0,0 of the screen. You can use ClientToScreen function to determine the window position which client area will be on the 0,0 of the screen.
After setting up the DirectDraw move the window back to it's original position but there is a problem, if you move the window immediately after setting up the DirectDraw issue persists. (I believe clipper setting functions works async). To solve that you can set a windows timer , right after setting the DirectDraw set a timer (1 second got the job done in my case) and move window back to it's original position when the timer updates.
To summarize the process :
Move window to a new position which client area of the window will be on the 0,0 of the screen.
Set up the clipper
Set a timer (1 second worked in my case)
When timer updates move window back the it's original position.
But still if someone knows the proper solution it would be nice.

How to draw buttons in TStringGrid cells

I am trying to customize a TStringGrid by adding visual objects to cells within the grid. One column needs to contain standard windows push buttons in each row and another column needs to contain a drop down with pre-defined options.
From what I have read the best way to achieve this is to draw the buttons manually in the OnDrawCell event handler. All of the examples I have found use DrawFrameControl() which does not draw a themed button like you would expect in Windows 7 or later.
Is there an equivalent function to DrawFrameControl() that will allow me to draw a themed button and if so can someone please give an example of how I might use it?
I also tried creating a vector of TButtons and setting the parent of each button to be the StringGrid and placing each button within the relevant cell. This also works but does now allow for scrolling of the grid when there are more cells that can be displayed visible area.
I am using RAD Studio 10.2 C++ builder and using the BCC32C compiler (clang-enhanced). It is a VCL WIN32 application.
Is there an equivalent function to DrawFrameControl() that will allow me to draw a themed button
The Win32 DrawFrameControl() function is for drawing non-themed UI controls. To draw themed UI controls, you need to use the Win32 Theming functions instead - DrawThemeBackground(), DrawThemeEdge(), DrawThemeText(), etc. These functions are wrapped for you by the VCL's Vcl.Themes unit. In particular, use the TThemeServices class, which has various Draw...() methods that you can use when TThemeServices.Available and TThemeServices.Enabled are both true.
I also tried creating a vector of TButtons and setting the parent of each button to be the StringGrid and placing each button within the relevant cell. This also works but does now allow for scrolling of the grid when there are more cells that can be displayed visible area.
Correct. You would have to subclass the StringGrid to intercept the scrolling so you can reposition the buttons manually.
Just for completeness here is the code I got working in order to draw a Windows Themed button in a TStringGrid cell:
void __fastcall TForm_Controller::StringGrid1DrawCell(TObject *Sender, int ACol,
int ARow, TRect &Rect, TGridDrawState State)
{
TStringGrid *grid;
bool ButtonDown = false, ButtonHot = false, ButtonInFocus = false;
TThemedElementDetails LDetails;
TTextFormatFlags LTextFormat;
TColor LColor, TempColor;
TCustomStyleServices *LStyle;
int XPos, YPos;
TPoint points[3];
grid = (TStringGrid *)Sender;
//a cell with a button ('+' or '-')
if((ACol == 0) && (ARow > 0) && grid->Cells[ACol][ARow].Length())
{
Rect.Left -= 4; //override padding so button fills entire cell
if ((FocusCell.X == ACol) && (FocusCell.Y == ARow))
ButtonHot = true;
if ((CellDown.X == ACol) && (CellDown.Y == ARow))
ButtonDown = true;
LStyle = StyleServices();
if (LStyle->Enabled && LStyle->Available)
{
if (ButtonDown)
LDetails = LStyle->GetElementDetails(tbPushButtonPressed);
else if (ButtonHot)
LDetails = LStyle->GetElementDetails(tbPushButtonHot);
else if (ButtonInFocus)
LDetails = LStyle->GetElementDetails(tbPushButtonDefaulted);
else
LDetails = LStyle->GetElementDetails(tbPushButtonNormal);
LStyle->DrawElement(grid->Canvas->Handle, LDetails, Rect);
if (LStyle->GetElementColor(LDetails, ecTextColor, LColor))
grid->Canvas->Font->Color = LColor;
grid->Canvas->Font->Size = 13;
LTextFormat = (tfCenter);
LStyle->DrawTextA(grid->Canvas->Handle, LDetails, grid->Cells[ACol][ARow], Rect, TTextFormat() << tfCenter << tfVerticalCenter);
}
else //themed drawing not available so revert to old style
DrawButtonFace(grid->Canvas, Rect, 1, bsAutoDetect, true, ButtonDown, ButtonInFocus);
}
}
I then use the OnMouseDown, OnMouseMove, OnMouseLeave and OnMouseUp events to determine what state the buttons need to be in using 3 TPoint objects FocusCell, PrevCell, CellDown.

Make a QDialog appear in a different screen

The title says it pretty much all:
I have two screens, and each time I create a QDialog it appears in the same screen as its parent.
How can I make it appear in a different screen? Or should I use a different type of top-level widget?
The code I use to create the dialog is:
QDialog my_dialog = new QDialog(this,
Qt::WindowMaximizeButtonHint |
Qt::WindowCloseButtonHint);
...
EDIT:
I have also tried using the QDesktopWidget which gives me a QScreen object that refers to the second screen. But then I don't find how to instruct the QDialog to use that QScreen (setting it as the parent doesn't work).
It is bad, that you edit your question without reading comments :(
// Your screen geometry:
QRect buildScreenGeometry()
{
auto desktop = QApplication::desktop();
QRect virtualRect;
const auto n = desktop->screenCount();
for ( auto i = 0; i < n; i++ )
virtualRect |= desktop->screenGeometry(i);
return virtualRect;
}
// Moving
auto dlg = new QDialog( someParent );
auto newPoint = QPoint( 2000, 0 ); // point on another screen
auto realPos = someParent->mapFromGlobal( newPoint );
dlg->move( realPos );
That's all.
UPDATE:
You should understand, that there are only ONE screen area with COMMON coordinate system, that contains ALL screens.
For example, you have 2 monitors with 800x600 resolution. First (main) monitor is standing left, and second standing right. In this case, coordinate system, that is available for your application is 1600x600. So, if your widget has 100x100 top-left position, on a first monitor, and you want to move it to another, you should call move(900x100); // 900 == screen1.width() + dialog.pos().x(). Then your widget will have 100x100 position on second monitor.
You should read Qt documentation.
You can use move on your QDialog, but be aware that move will set the QDialog position relative to it's parent.
You can get the Main Window's screen position and use that to setup the QDialog position. Just know that you're not guaranteed to have 2 screens on the end user machine.
For more information on move see: http://doc.qt.io/qt-5/application-windows.html#window-geometry

Win7 64bits Professional. GDI doesn't work normally occasionally until resize the window

In our project, we use GDI to draw waveform and any other graphics, however, we meet a special problem, the situations are:
The waveform stop drawing, just like not response.
The buttons in toolbar also stop updating its background while mouse hots it or clicks it, however, it is very mystical, the button could respond event and open the relevant dialog.
The dialog opened from toolbar could draw normally, any figures could work well.
While resize the window, double click the title of application, anything works normally again.
So, I hope to know whether there is any bug or driven problem in Win7 64bits Pro version which have been reported.
The similar problems in stack-overflow see this link:
What could cause redraw issues on 64-bit vista but not in 32-bit in .NET WInForms?
The code of drawing waveform and graphics, and
void CZMultiPatientView::UpdateDisplay(int ThisSecondCount, int ThisMillisecondCount)
{
CClientDC dc(this);
CDC *pDC = &dc;
//
// Draw waveforms
//
DrawPatientViewWaveforms(pDC);
//
// Update parameters
//
if ((GetElapsedMilliseconds(mLastAlarmMillisecondCount, ThisMillisecondCount) >= 500) || (mForceRedraw))
{
//
// !!! SHOULD NOT DO THIS IN HERE !!!
//
if (mSetupParameterDialogDisplayed)
{
//mParameterDataDialog.UpdateCurrentParameterValues() ;
m_pParamDlg->SendMessage(WM_UPDATE_VALUE); // Kevin
}
}
if ((GetElapsedSeconds(mLastAlarmsecondCount, ThisSecondCount) >= 1) || (mForceRedraw))
{
//Update messages (once a second)
UpdateMessages(pDC);
mLastAlarmsecondCount=ThisSecondCount;
}
if (GetElapsedMilliseconds(mLastDrawParametersCount, ThisMillisecondCount) >= 200 || (mForceRedraw))
{
PostMessage(APP_UPDATE_VIEWS, (WPARAM)ThisMillisecondCount, (LPARAM)mForceRedraw);
mLastDrawParametersCount = ThisMillisecondCount;
}
//
// Update alarms
//
if (GetElapsedMilliseconds(mLastAlarmMillisecondCount, ThisMillisecondCount) >= 500)
{
mLastAlarmMillisecondCount = ThisMillisecondCount ;
DoSoundAlarmTone();
}
mForceRedraw = 0 ;
}