How do you use GdkRectangle to determine whether you size-allocate is growing or shrinking? - scroll

I have a callback for the size-allocate signal on my GtkScrolledWindow. I want to scroll to the right when I am adding stuff to that window. This works fine but introduces a subtle bug when removing items from that window. I would like to only scroll the window when adding stuff. I see the signal receives a GdkRectangle but I am unsure how to use it.

First size-allocate signal run-first, that means, If I'm not wrong, before the default handler. So you can get the GdkRectangle of the widget with gtk_widget_get_allocation, and compare it with the new one.
Now GdkRectangle is a cairo_rectangle_int_t and the definition of that is:
typedef struct {
int x, y;
int width, height;
} cairo_rectangle_int_t;
So you can check width and heights, with the old ones.

Related

Questions regarding GetWindowPlacement return data

I'm a bit unsure of the meaning of some of the return values from a call to the GetWindowPlacement() function, so I'd like your help, please.
I'll be calling this to obtain the normal dimensions of a hidden window.
First, where do the values of the showCmd field come from? In the Microsoft documentation of the return structure (WINDOWPLACEMENT structure, all the descriptions of the possible values use verbs/action words; e.g., "SW_MAXIMIZE: Maximizes the specified window", or "SW_SHOWNOACTIVATE: Displays a window in its most recent size and position."
I want to obtain the dimensions of the hidden window without unhiding/restoring it first, so with the verbs it seems that I would have to call SetWindowPlacement() with showCmd set to SW_SHOWNOACTIVATE before calling GetWindowPlacement. Is that correct?
So do I understand correctly that the primary (and perhaps only) way that field gets its various values is by an explicit call to SetWindowPlacement() somewhere?
My second question relates to the rcNormalPosition return values. Do those data include the window decorations, or are they client values?
Thank you for your time!
The meaning of the showCmd member of the WINDOWPLACEMENT struct is a bit confusing because Win32 is reusing the SW_* commands used by ShowWindow().
Luckily, the meaning is documented on the GetWindowPlacement() function.
If the window identified by the hWnd parameter is maximized, the
showCmd member is SW_SHOWMAXIMIZED. If the window is minimized,
showCmd is SW_SHOWMINIMIZED. Otherwise, it is SW_SHOWNORMAL.
So, based on which of those 3 values is returned, you can tell whether the window is currently maximized, minimized or, normal (restored). And if you'd like to know what the normal placement is, you can just use the rcNormalPosition member. You do not need to call SetWindowPlacement() at all.
However, heed the warning that GetWindowPlacement() returns workspace coordinates rather than screen coordinates, which differ based on taskbar position and size. This is not a problem if you are only using the coordinates returned by GetWindowPlacement() to call SetWindowPlacement(). Otherwise, you might have to find a way to convert from workspace to screen coordinates.
I found these 2 functions to work for me.
void MyDialog::LoadDialogPlacement()
{
static WINDOWPLACEMENT last_wp = {};
// Load last stored DB version
WINDOWPLACEMENT *wp = new WINDOWPLACEMENT;
GetStoredWindowPlacement(&wp);
if (memcmp((void *)&last_wp, (const void *)wp, sizeof(WINDOWPLACEMENT)) == 0) return;
memcpy((void *)&last_wp, (const void *)wp, sizeof(WINDOWPLACEMENT));
SetWindowPlacement(wp);
delete[] wp;
}
void MyDialog::SaveDialogPlacement()
{
static WINDOWPLACEMENT last_wp = {};
if (IsWindowVisible())
{
WINDOWPLACEMENT wp = {};
wp.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(&wp);
if (memcmp((void *)&last_wp, (const void *)&wp, wp.length) == 0) return;
memcpy((void *)&last_wp, (const void *)&wp, wp.length);
StoreWindowPlacement(&wp);
}
}

CRect member variables have strange values

I'm trying to use the member variables from my client rect, but they are holding extremely negative values, like -858993460. Even when I call rect.Width(), it returns an extremely negative number. I need the values to determine the corresponding section of a wave file to play when I select the wave that I have drawn on the screen. Would anyone happen to know why it could be doing this?
Note: I threw int's right, left, and width in just to see what values they are holding. I really only need rect.Width() to scale the selection to be able to access the data array of my wave file.
void CWaveEditView::OnToolsPlay32775()
{
// TODO: Add your command handler code here
CWaveEditDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if(!pDoc){
return;
}
if(pDoc->wave.hdr==NULL){
return;
}
if(selectionStart!=selectionEnd){
CRect rect;
GetClientRect(&rect);
rect.NormalizeRect();
int right = rect.right;
int left = rect.left;
int width = rect.Width();
int startms=(1000.0*pDoc->wave.lastSample/pDoc->wave.sampleRate)*selectionStart/rect.Width();
int endms=(1000.0*pDoc->wave.lastSample/pDoc->wave.sampleRate)*selectionEnd/rect.Width();
WaveFile * selection = new WaveFile(pDoc->wave.numChannels, pDoc->wave.sampleRate, pDoc->wave.bitsPerSample);
while(startms<=endms){
selection->add_sample(pDoc->wave.get_sample(startms));
startms++;
}
selection->updateHeader();
selection->play();
delete selection;
}
The default constructor of CRect does not initialise its members (because it is a thin wrapper for the RECT structure). You could initialise it to (0,0,0,0) and check whether or not it is empty after your call to GetClientRect.
Since GetClientRect appears to be failing, you may want to check that your window handle is valid using GetSafeHwnd().

Cannot get XCreateSimpleWindow to open window at the right position

The following code opens a window of the right size, w,h, but not at the correct position, x,y.
#include <iostream>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
using namespace std;
int main(int argc, char* argv[]){
Display *display; // A connection to X server
int screen_number;
Window canvas_window;
unsigned long white_pixel;
unsigned long black_pixel;
display = XOpenDisplay(NULL); // Connect X server by opening a display
if(!display){
cerr<<"Unable to connect X server\n";
return 1;
}
screen_number = DefaultScreen(display);
white_pixel = WhitePixel(display, screen_number);
black_pixel = BlackPixel(display, screen_number);
int x=0, y=100, w=300, h=400;
canvas_window = XCreateSimpleWindow(display,
RootWindow(display, screen_number),
x,y, // top left corner
w,h, // width and height
2, // border width
black_pixel,
white_pixel);
XMapWindow(display, canvas_window); // Map canvas window to display
XSync(display, False);
cin >> x; // just so that the program does not end
}
I compiled this with g++ xwindowtest.cpp -lX11 where g++ is version 4.6.2 and ran under Debian GNU/Linux.
The above solution is sort of correct, but not complete.
Creating a new top-level window on the desktop, and creating a new (child) window within the top-level window of your application use the same XCreateSimpleWindow() call, but the actual behaviour can be different.
When creating a new child window within your application you are in charge, and the origin coordinates (relative to its parent window's origin) and size you give for the new window will be honoured. In other words the window will go where you want it to.
However when creating a new top-level window on the desktop you have to deal with the pesky window manager, for example Motif, KDE, Gnome, etc. This intervenes when you create a top-level window to add borders ("decoration"), title, possibly icons, etc. More to the point it will, by default, ignore your requested origin coordinates in most cases and put the new window where it wants rather than where you asked it to put it. It is only when it has been mapped (somewhere) that you can then move it with XMoveWindow().
To avoid this you can ask, or in X11-speak "Hint to", the Window manager that "no, I want you to put the window where I ask, not where you want to put it". You do this with the following sequence:
(1) Define a XSizeHints structure.
(2) Set the flags bit in this structure with a mask of what you want to specify
(3) Populate the relevant arguments
(4) Call XSetNormalHints() on the newly created window (before you map it).
So in C code you would do:
XSizeHints my_hints = {0};
my_hints.flags = PPosition | PSize; /* I want to specify position and size */
my_hints.x = wanted_x_origin; /* The origin and size coords I want */
my_hints.y = wanted_y_origin;
my_hints.width = wanted_width;
my_hints.height = wanted_height;
XSetNormalHints(disp, new_window, &my_hints); /* Where new_window is the new window */
Then map it and - hopefully - it will be where you want it.
I usually declare a XSizeHints first and assign x,y coordinates etc to hints.
When creating x window you could do
XCreateSimpleWindow(display,
DefaultRootWindow(display),
hints.x, hints.y,
hints.width,hints.height,
borderWidth,
blackPixel, whitePixel)
That always works for me with 100% correct windows location.
I had the same problem. I am just starting with X11. Maybe others with more experience can clarify why this works (and simply specifying the x, y for XCreateSimpleWindow does not).
Here's my fix:
disp is your display, win0 is your canvas_window:
XMoveWindow(disp, win0, 200, 200);
XSync (disp, FALSE);
..... do something .....
XMoveWindow(disp, win0, 0, 0);
XSync (disp, FALSE);
... do something
When I run this code snippet, the window moves. You need to follow the XMoveWindow by XSync so that requests (such as a move) are handled appropriately.

How to maintain widgets aspect ratio in Qt?

How is it possible to maintain widgets aspect ratio in Qt and what about centering the widget?
You don't have to implement your own layout manager. You can do with inheriting QWidget and reimplementing
int QWidget::heightForWidth( int w ) { return w; }
to stay square. However, heightForWidth() doesn't work on toplevel windows on X11, since apparently the X11 protocol doesn't support that. As for centering, you can pass Qt::AlignCenter as the third parameter of QBoxLayout::addWidget() or the fifth parameter of QGridLayout::addWidget().
Note: In newer versions of Qt at least, QWidget does not have the heightForWidth or widthForHeight anymore (so they cannot be overriden), and therefore setWidthForHeight(true) or setHeightForWidth(true) only have an effect for descendants of QGraphicsLayout.
The right answer is to create your custom layout manager. That is possible by subclassing QLayout.
Methods to implement when subclassing QLayout
void addItem(QLayoutItem* item);
Adds item to layout.
int count() const;
Returns the item count.
QLayoutItem* itemAt(int index) const;
Returns item reference at index or 0 if there's none.
QLayoutItem* takeAt(int index);
Takes and returns item from the layout from index or returns 0 if there is none.
Qt::Orientations expandingDirections() const;
Returns the layouts expanding directions.
bool hasHeightForWidth() const;
Tells if the layout handles height for width calculation.
QSize minimumSize() const;
Returns the layouts minimum size.
void setGeometry(const QRect& rect);
Sets the geometry of the layout and the items inside it. Here you have to maintain the aspect ratio and do the centering.
QSize sizeHint() const;
Returns the preferred size for the layout.
Further reading
Maintaining square form for a widget in Qt # Forum Nokia
Implementing a layout manager in Qt # Forum Nokia
Writing custom layout managers # Qt documentation
Calling resize() from within resizeEvent() has never worked well for me -- at best it will cause flickering as the window is resized twice (as you have), at worst an infinite loop.
I think the "correct" way to maintain a fixed aspect ratio is to create a custom layout. You'll have to override just two methods, QLayoutItem::hasHeightForWidth() and QLayoutItem::heightForWidth().
I too was trying to achieve the requested effect: a widget that keeps a fixed aspect ratio while staying centred in its allocated space. At first I tried other answers from this question:
implementing heightForWidth and hasHeightForWidth as suggested by marc-mutz-mmutz simply didn't work for me.
I briefly looked at implementing a custom layout manager, but all Bleadof's links were dead, and when I found the documentation and read through it, it looked way too complicated for what I was trying to achieve.
I ended up creating a custom widget that responds to resizeEvent and uses setContentsMargin to set margins such that the remaining content area keeps the desired ratio.
I found I also had to set the widget's size policy to QSizePolicy::Ignored in both directions to avoid odd resizing issues resulting from the size requests of child widgets—the end result is that my widget accepts whatever size its parent allocates to it (and then sets its margins as described above to keep the desired aspect ratio in its content area).
My code looks like this:
from PySide2.QtWidgets import QWidget, QSizePolicy
class AspectWidget(QWidget):
'''
A widget that maintains its aspect ratio.
'''
def __init__(self, *args, ratio=4/3, **kwargs):
super().__init__(*args, **kwargs)
self.ratio = ratio
self.adjusted_to_size = (-1, -1)
self.setSizePolicy(QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored))
def resizeEvent(self, event):
size = event.size()
if size == self.adjusted_to_size:
# Avoid infinite recursion. I suspect Qt does this for you,
# but it's best to be safe.
return
self.adjusted_to_size = size
full_width = size.width()
full_height = size.height()
width = min(full_width, full_height * self.ratio)
height = min(full_height, full_width / self.ratio)
h_margin = round((full_width - width) / 2)
v_margin = round((full_height - height) / 2)
self.setContentsMargins(h_margin, v_margin, h_margin, v_margin)
(Obviously, this code is in Python, but it should be straightforward to express in C++ or your language of choice.)
In my case overriding heightForWidth() doesn't work. And, for someone, it could be helpful to get working example of using resize event.
At first subclass qObject to create filter. More about event filters.
class FilterObject:public QObject{
public:
QWidget *target = nullptr;//it holds a pointer to target object
int goalHeight=0;
FilterObject(QObject *parent=nullptr):QObject(parent){}//uses QObject constructor
bool eventFilter(QObject *watched, QEvent *event) override;//and overrides eventFilter function
};
Then eventFilter function. It's code should be defined outside of FilterObject definition to prevent warning. Thanks to this answer.
bool FilterObject::eventFilter(QObject *watched, QEvent *event) {
if(watched!=target){//checks for correct target object.
return false;
}
if(event->type()!=QEvent::Resize){//and correct event
return false;
}
QResizeEvent *resEvent = static_cast<QResizeEvent*>(event);//then sets correct event type
goalHeight = 7*resEvent->size().width()/16;//calculates height, 7/16 of width in my case
if(target->height()!=goalHeight){
target->setFixedHeight(goalHeight);
}
return true;
};
And then in main code create FilterObject and set it as EventFilter listener to target object. Thanks to this answer.
FilterObject *filter = new FilterObject();
QWidget *targetWidget = new QWidget();//let it be target object
filter->target=targetWidget;
targetWidget->installEventFilter(filter);
Now filter will receive all targetWidget's events and set correct height at resize event.

Resize Windows OnScreen keyboard programmatically

I wonder if it is possible to resize Windows OnScreen-keyboard in my program? What Windows methods to use for that?
simply use standard Win32 api.
I know this question is old, but the given answer is really short. To add value to this topic I could not resist to add the following information:
You could do something like this, the flag SWP_NOREPOSITION should make the iPosX and iPosY to be ignored by SetWindowPos. So only the width and height should change. I have not tested this code though.
HWND hWndOSK = FindWindow("IPTip_Main_Window", null); //Only the class is known, the window has no name
int iPosX=0;
int iPosY=0;
int iWidth=1000;
int iHeight=600;
if(hWndOSK != NULL)
{
//Window is up
if(!SetWindowPos(hWndOSK, HWND_TOPMOST, iPosX, iPosY, iWidth, iHeight, SWP_NOREPOSITION))
{
//Something went wrong do some error handling
}
}
SetWindowPos: http://msdn.microsoft.com/en-us/library/ms633545.aspx
FindWindow: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633499(v=vs.85).aspx

Resources