Python curses - resizing/scrolling the screen - python-3.x

I am creating a terminal-based RPG game. Recently, due to issues with the CMD (flickering when refreshing and other problems) I decided to move to curses.
I encountered issues with screen capacity during, say, long dialogues. In the CMD the screen just scrolled automatically - and that is what I am looking for.
My approach was as follows. I have a number of scripts containing classes and functions grouped according to functionality (such as ones pertaining to the board, to the player, NPCs, general utility functions script etc.). All of them also require access to some shared variables and objects; I group those in a shared.py script and subscribe the remaining scripts to it; the portion of that script relevant to the display mechanism looks like this:
shared.py
import curses
sc = curses.initscr()
scr = curses.newpad(1000,1000)
scr.scrollok
And for refreshing I use:
shared.scr.refresh(0, 0, 0, 0, shared.sc.getmaxyx()[0] - 1, shared.sc.getmaxyx()[1] - 1)
But at the moment, when the display fills up, the new content is, I believe, still being dumped into the pad, but is not visible on the display. I could probably come up with a way of shifting the arguments of refresh() so that the bottom line of the display is always coincident with the most recent line added to the pad, but that still only gives me one screen's worth of visibility.
Is it possible to print the contents of the pad into the window in such a way so that the old contents are retained and accessible by scrolling up? Effectively, I want to be able to keep adding lines to my display and as it fills up, I want more display area to be generated and the old content that no longer fits inside the display to move out through the top edge of the display (but for it to still be accessible by scrolling).

Related

Drawing Custom Context Menus Anywhere on Desktop

I'm trying to figure out a way to draw a context menu foo at the cursor's current position no matter where on screen it is (i.e. over a window that has nothing to do with my program), and I can't seem to find a clean way of doing this, as all the libraries I can find define context menus upon the current window.
The things that come to mind for me are:
A: Drawing a tiny window at the cursor and then immediately opening up a context window
B: Drawing borderless windows that act like context menus
C: Drawing directly to the root window
However, none of these seem like clean and portable solutions, so I figured I would ask before diving into code.
I know that this is not what context menus were designed for, but the look fits my application very well. I would prefer to use Qt to keep things portable across systems, but at the moment I really only care about X on Linux.
Edit: 1st paragraph expansion

How to make an overlay which capture no events

I would like to draw some sort of window on top of all the other windows. For example, to display some debugging infos (like conky) or things like a timer.
The main thing is that I would like to able to continue using the other windows while using it (the events go through transparently).
I've tried doing it with pygtk, pyqt and others but can't find a way to make it a real overlay with no event capture.
Is there some low-level x11 solution?
I think the Composite-extension-approach will not work when a compositing manager is running (and thus Composite's overlay window is already used).
Since you explicitly mention "no event capture":
The SHAPE extension allows to set some different shapes for a window. Version 1.1 of this extension added the "input" shape. Just setting this to an empty region should pretty much do what you want.
Some concrete example of exactly what I think you ask for can be found in Conky's source code: http://sources.debian.net/src/conky/1.10.3-1/src/x11.cc/?hl=769#L764-L781
Edit: Since you said that you didn't find anything in Gtk (well, PyGtk), here is the function that you need in Gtk: https://developer.gnome.org/gdk3/stable/gdk3-Windows.html#gdk-window-input-shape-combine-region
You might need Composite extension + GetOverlayWindow request:
Version 0.3 of the protocol adds the Composite Overlay Window, which
provides compositing managers with a surface on which to draw without
interference. This window is always above normal windows and is always
below the screen saver window. It is an InputOutput window whose width
and height are the screen dimensions. Its visual is the root visual
and its border width is zero. Attempts to redirect it using the
composite extension are ignored. This window does not appear in the
reply of the QueryTree request. It is also an override redirect
window. These last two features make it invisible to window managers
and other X11 clients. The only way to access the XID of this window
is via the CompositeGetOverlayWindow request. Initially, the Composite
Overlay Window is unmapped.
CompositeGetOverlayWindow returns the XID of the Composite Overlay
Window. If the window has not yet been mapped, it is mapped by this
request. When all clients who have called this request have terminated
their X11 connections the window is unmapped.
Composite managers may render directly to the Composite Overlay
Window, or they may reparent other windows to be children of this
window and render to these. Multiple clients may render to the
Composite Overlay Window, create child windows of it, reshape it, and
redefine its input region, but the specific arbitration rules followed
by these clients is not defined by this specification; these policies
should be defined by the clients themselves.
C api : XCompositeGetOverlayWindow
PyGTK Solution:
I think the composite and shapes X extensions are sufficiently ubiquitous and shall assume here that they are active on your system. Here's PyGtk code for this:
# avoid title bar and standard window minimize, maximize, close buttons
win.set_decorated(False)
# make the window stick above all others (super button will still override it in the z-order, which is fine)
win.set_keep_above(True)
# make events pass through
region = cairo.Region(cairo.RectangleInt(0, 0, 0, 0))
my_window.input_shape_combine_region(region)
win.show_all()
# set the entire window to be semi-transparent, if we like
win.set_opacity(0.2)
Basically what this does is tell Gtk that other than pixel (0,0) the entire window my_window should not be considered part of itself in terms of event propagation. That in turn, according to my current understanding means that when the pointer moves and clicks, the events go to the underlying window under the pointer position, as if my_window was not there.
Caveat:
This does allow your overlay window being the focus window (due to user-solicited window switching or just because it pops up and gets the focus when your application starts). Which means that for example, keyboard events will still undesirably go to it up until the user has clicked through it to make it lose focus in favor of whatever window is under the cursor. I would likely use the approach described here to iron out this aspect.
If there's a different and proper approach for making a portion of the screen "display stuff but not receive events", without building an oddball window like above over it, I'm happy to learn about it.
I assume that one's particular desktop environment (gnome, unity, etc. on linux) may interfere with this solution depending on version and configuration, on some occasions.

Weird results when trying to get UI elements to fit a dynamic size in Unity

I have a system where if you walk by a sign it will create a popup dialogue which is fine (just the popup part) but when I try to make it to where it can be adjusted based on how much text is displayed (Content Size Fitter) then I get something that literally does not make any sense to me whatsoever. When using World Space my font on Text components has to be 0 (also makes no sense) so that 1 letter isn't the size of 100 units and the combination of these 2 issues has almost made me go mad but that is the reason why I am here so you all can save me!
My setup for my sign :
Now this is the dialogue that is spawned viewed from the inspector (Not shown in the scene/game view yet) :
Now this is when the player walks near the sign with all the components you see in the screenshots :
As you can see the height of my dialoguePanel for some reason keeps going to 321 and New Years isn't close so this countdown I am not happy with. It should be adjusting to how much text is in it. I mean I just did a tooltip almost 100% identical except that the Canvas isn't World Space but Screen Space - Overlay. On top of all this it seems any text I use in World Space HAS to be font 0. Please help I am about to lose my mind.
World space canvas is a bit tricky. And guess what is even more tricky: content size fitter. One of solutions is that you add your dialog UI element manually in the scene at desired location and tweak its RectTransform values in inspector to get what you want to see in scene view and then save it as prefab.
Read more about How Content Size Fitter works and there is one more thing about UI when working with world space canvas. UI is way too bigger than your other scene elements. To solve this problem you have to scale it down as instructed in section Specify the size of the Canvas in the world.
Hope it helps :)

wxWidgets Linux GCC, how to add scroll bar into wxFrame

My application has a GUI, it first reads a initialization file and then decides how many control objects (e.g., wxTextCtrl, wxToggleButton, etc.) need to be added to a wxFrame. When there are too many objects on the wxFrame, some objects are out of visible boundary, i.e., they are on the wxFrame, but user can not see them.
I am wondering whether it is possible to add a vertical and a horizontal scroll bar into wxFrame.
Thanks.
You should not add controls to a wxFrame. The wxFrame can be used to hold windows, including scrolled windows, on which controls can be placed.
Take a look at some of the sample apps in the distribution to see how this works.

How to determine visible region of a Windows in X Windows / Linux?

I have several nested X Windows - let's say - a scrollable window within a scrollable window (see the example below). In such case the main window contains (at least) the major scroll bars and the (major) drawing area they control. This drawing area on its turn contains (at least) a scrollable window batch - a (minor) main window, containing a scroll bar and minor drawing area.
During live scrolling of an inner drawing area the redraw procedure messes up, because I am using the XCopyArea to speed the process and move the contents that are valid and invoke the actual redraw routine for just the newly appeared content. This works fine when the inner drawing batch is by itself, but when nested within another one a problem occurs - when the inner scrolling-batck is partially visible (i.e. the major drawing area is scrolled) redrawing of newly appeared contents is clipped from the major drawing area and never actually redrawn, but considered to be so. When on the next scroll XCopyArea gets this supposedly-redrawn area it is actually empty. Finally this empty area show up on the partially visible inner scrolling-batch and it is empty. On the first general redraw message they are fixed.
If I can obtain the clipping mask for what is actually visible from (my) inner drawing area I can adjust the XCopyArea() call and redraw call and overcome the problem without the plan "B" which is redrawing all contents on each scroll bar movement.
Example: Developing a plugin for Mozilla Firefox and needing to determine the region that describes the visible area of "my" window, i.e. the one that is passed from the Mozilla system as plugin viewport.
If its really an X Window you get, and not a widget from some specific toolkit (like GTK+ maybe?) then you can use the XGetWindowAttributes function call.
This fills out a provided XWindowAttributes structure, which includes integers for the x and y position of the window as well as its width and height and other useful facts.
But in reality I think you are probably using the Mozilla plugin API inherited from Netscape, aka NSAPI, and in that case what you get is a call to your function NPP_SetWindow() at least once (and again if necessary because something changed) with a structure which contains the information you're looking for. Try looking at http://www.mozilla.org/projects/plugins/ for more information about the APIs you should use.

Resources