I need a simple image viewer widget to display a Pixbuf, with a zoom factor that can be changed using the scroll wheel (integer factors only, nearest neighbor interpolation), zooming in should adjust the scroll position such that the current center or mouse position will be the origin. Clicking and dragging the mouse should move the surface accordingly; basically what eog or evince do.
There was once an external gtk-image-viewer component for GTK2, but I haven't found anything else…
So I tried implementing my own and this is how far I came:
struct ZoomableImage : public Gtk::Scrollable, public Gtk::DrawingArea {
ZoomableImage() {
auto h = get_hadjustment();
}
};
Which leads to a warning
gtk_scrollable_get_hadjustment: assertion `GTK_IS_SCROLLABLE (scrollable)' failed
I couldn't find any proper documentation about how to inherit interfaces in GTKmm, the headers hide a constructor from doxygen which is supposed to be called with the result of a base class's init() function?! Some examples initialize Glib::ObjectBase(typeid(ZoomableImage)), which only adds more errors.
(My idea was to put my ZoomableImage in a ScrolledWindow which should provide me with H/V-adjustments, these range from 0 to the image's real height/width, in on_draw, I would read the adjustment's value, apply the zoom factor and draw the Pixbuf accordingly. Would this make sense?)
Related
I am trying to spread out the instantiated objects to fill up the grey area in a grid layout. So far I am stuck at this point where I have all the objects stacked on eachother. I did try a few things but they would make the object not visible. Here is the code I have and two pictures. One of the scene and one of the hierarchy. scene picture hierarchy picture
public class stockSpawner : MonoBehaviour
{
[SerializeField] GameObject stockPrefab;
int x;
void Start()
{
x = Mathf.RoundToInt(scene2Calc.nS);
}
void Update()
{
if (x >= 1)
{
Instantiate(stockPrefab, transform);
x--;
}
else { Debug.Log(x + "this is x value");}
}
}
It seems all of your assets are UI. If you want to create a grid, normally I would say to instantiate the objects and change the transform at which they spawn in a double loop. In one loop you would iterate the horizontal axis of spawning while the other moves the vertical. However, as your setup is all UI, you can use some nifty components to do all the heavy lifting for you.
Attach a grid layout group to the parent object of where you want to spawn all of these UI objects. I would recommend attaching this component to the Panel in your screenshot. I would also recommend changing your installation code slightly as you are working with UI objects. To assure anchoring, rescaling, etc. work, you will want to use Instantiate(stockPrefab, transform, false);. That last parameter is instantiateInWorldSpace, which from the docs,
When you assign a parent Object, pass true to position the new object
directly in world space. Pass false to set the Object’s position
relative to its new parent..
Now getting back to the main portion of your question. If you added the grid layout component to your panel, the objects will now be aligned into a grid. There are various different fields on this component you can change. They are on the docs, but I will also list them here for clarity.
Padding The padding inside the edges of the layout group.
Cell Size The size to use for each layout element in the group.
Spacing The spacing between the layout elements.
Start Corner The corner where the first element is located.
Start Axis Which primary axis to place elements along. Horizontal will fill an entire row before a new row is started. Vertical will fill an entire column before a new column is started.
Child Alignment The alignment to use for the layout elements if they don't fill out all the available space.
Constraint Constraint the grid to a fixed number of rows or columns to aid the auto layout system.
If you properly fill out all of these fields, your UI objects when spawned and childed to the Panel object that has this grid layout component will now not be on top of each other, but will form a grid.
I have canvas with vertical layout and 2 elements within (in fact it's element with only recttransform on it, let's call it container). So these 2 containers take a half of the screen by height and stretched by width, ok. How can I place an text element in above container and snap it to the bottom of this container? I tried press bottom button in recttransform widget (also with shift and alt) and it seems it doesn't affect my transform at all
P.s. May be I can use some free plugin instead of default unity components of UI layout?
There are different ways of placing your UI elements
Simply drag and drop it to the bottom where you want it
Use the anchor widget to set the anchoring to bottom with horizontal stretch and hold shift to also set pivot. Then set Pos Y to 0. Set Left and Right to 0.
Assuming you also want other elements in your containers, place a Vertical Layout Group on each container and make sure that your text element is the last child of the container in the hierarchy.
I would also advise you to seek out tutorials on Unity UI anchoring, positioning, scaling, and layout. You need a deeper understanding of how these things interact than you are likely to get from Stack Overflow. Otherwise you will suddenly find that your UI behaves in unexpected ways when rearranged or displayed on a different aspect ratio.
It's fairly easy with Unity UI system. You just need to get used to it. Here are simple steps to accomplish what you want:
Create Text element as a child of that container.
Select your newly created element and edit its RectTransform component values:
2.1. Set both Y axis anchors (min and max) to 0.
2.2. Set pivot value to 0 as well.
2.3. Set Pos Y value to 0 as well.
Now your Text element is anchored at the bottom of the container and its position (and height) is measured from the bottom of the Text element itself.
I have trouble making a window in GTKmm (C++, GTK+, GTKmm 3.22).
The window itself is empty (containing "Hello world").
What I want is that the window's height get set to the maximum height possible for a window, as if it is maximized, while the width is kept at an arbitrary value (200px).
I have huge trouble finding anything in this documentation https://developer.gnome.org/gtkmm-tutorial/stable/ or even the gtkmm doc from my linux distro.
Where can I find this kind of info?
And what should I do?
Maybe you may do this by setting geometry hints:
void Gtk::Window::set_geometry_hints ( Widget& geometry_widget,
const Gdk::Geometry& geometry, Gdk::WindowHints geom_mask )
This function sets up hints about how a window can be resized by the
user.
You can set a minimum and maximum size; allowed resize increments
(e.g. for xterm, you can only resize by the size of a character);
aspect ratios; and more. See the Gdk::Geometry struct.
Parameters
geometry_widget Widget the geometry hints used to be applied to or nullptr. Since 3.20 this argument is ignored and GTK behaves as if
nullptr was set.
geometry Struct containing geometry information or nullptr.
geom_mask Mask indicating which struct fields should be paid attention to.
Cited from here
You could use the Gtk::Widget::set_size_request() to scale your window anyway you like.
Gdk::Display *gdkDisplay = Gdk::Display::get_default().get();
Gdk::Screen *gdkScreen = gdkDisplay->get_default_screen().get();
myWindow->set_size_request(200, gdkScreen->get_height() - 1);
Note that myWindow may be a Gtk::Window derived class, or an instance of Gtk::Window* .
I have a dropdown list on a filter panel which needs to stretch dynamically to fit the content as shown:
I have tried several content size fitters but cannot find anything, If possible I would like to set a max width it can expand to then truncate everything longer than that, I would also like it to expand only to the right with a right pivot point. I have found a similar example here: https://forum.unity3d.com/threads/resize-standard-dropdown-to-fit-content-width.400502/
Thanks!
Well. Lets start with the code from that Unity forum thread.
var widest = 0f;
foreach (var item in _inputMines.GetComponentsInChildren<Text>()) {
widest = Mathf.Max(item.preferredWidth, widest);
}
_inputMines.GetComponent<LayoutElement>().preferredWidth = widest + 40;
We want to have a max-width allowed, so any content longer than this will be truncated. So let's add that variable:
var maxWidth = 250f;
//or whatever value; you may wish this to be a property so you can edit it in the inspector
var widest = 0f;
foreach (var item in _inputMines.GetComponentsInChildren<Text>()) {
Now we use the smaller of the two width values. Then apply it to the content layout:
}
widest = Mathf.Min(maxWidth, widest);
_inputMines.GetComponent<LayoutElement>().preferredWidth = widest + 40;
The +40 should be retained because that deals with the scrollbar. Your maxWidth value should be chosen to account for this.
Finally we want the longer items to get cut off nicely.
Give each dropdown item a Rect Mask 2D component (Component -> UI -> Rect Mask 2D). The template object exists in the scene hierarchy before the game is run, just disabled. You can just add the component to the parent transform, the one with the image (so the text is clipped).
You'll need to make sure that the mask covers the same width as the image graphic and expands along with it, possibly slightly shorter on the X direction so the text gets cut off before the image border is drawn. This should happen automatically, but you will need to check and possibly make some alterations to the template object. Alternatively you can use an Image Mask, but you'll have to play with that one yourself, but it will allow for non-rectangular clipping.
That's it!
I have a Composite which I will place in an Absolute Panel, I want to be able to specify the location coordinates of the composite and place it at that location in the absolute panel.
Also, at run time, sometime I will have to change the location coordinates of the Composite and move it.
I could have use a grid or other panel but while moving the composit, I want to place a move animation, that's why I'm using an absolute panel.
How to specify the coordinates of the composite before placing it in the absolute panel?
the composite:
public class SlotView extends Composite
{
...
}
AbsolutePanel.setWidgetPosition() will change the location of a Widget displayed inside of an AbsolutePanel. This is limited only to using pixel-based offsets.
A more robust solution is to use a LayoutPanel, which supports the use of font- or box-relative positions. LayoutPanel also has support for animating transitions.