-
Notifications
You must be signed in to change notification settings - Fork 0
11. Stack select
Movement and selection of stacks/counters have been implemented. With this the base functionality of the engine is done.
A run down of the features:
Hoover - opens a window with a tiny image of the map below the counter(s); counters are shown in 100% scale; window deleted when you move the cursor (or hit ESC).
Left-click - selects the counter(s); all previous selections are undone.
SHIFT Left-click - adds to the current selection (previous selections are not undone).
Left-click non-counter - deletes all selections.
Double Left-click - opens a window with images of counters in stack order; in this window you can select/unselect counters and drag a counter to a new position (reorder); window is deleted when double left-clicking again on the stack (or hitting ESC).
Drag Left-click - on unselected counter(s) will move them to a new position (no selection is done); on one or more selected counter(s) will drag all selected counters (also those in other stacks) to a new position.
Right-click - will open a menu of actions that can be applied to this counter only.
A selection looks like this.
A selection draws a rectangle around the counter, here colored in red. The user should be able to chose a selection color. Note that the rectangle is drawn underneath the Moved-marker.
In Qt it is not possible to paint outside the surface of a widget. In order to paint a selection (and the Moved-marker) the widget needs to be expanded with a margin. The margin width is set at 9 pixels. The margin must be symmetric (have the same width all around the counter).
The position of the counter (its State coordinates) is the upper left corner of the counter including its margin.
A stack of counters is moved as a whole, that is to say that each counter in the stack is moved the same distance. Multiple stacks are also moved as a whole if all the counters are selected. It is not more difficult to implement multi-stack movement than single-stack movement because the basic functionality is the same.
When dragging stacks, an image of the dragged stacks is necessary as a visual feed-back. This image can be called a ghost image. The ghost image is a QPixmap generated from the counters. The code looks like this:
QImage CentralFrame::selectedGhostImage(QRect &totalRect)
{
// generate stacks of selected
for (auto obj = Counter::counters.begin(); obj != Counter::counters.end(); ++obj)
{
if (obj->second->selected == true)
{
Point p = (Point){.x = obj->second->state.x, .y = obj->second->state.y};
if (stacks.find( p ) == stacks.end())
{
// not found
Stack stack = {{obj->second->zorder, obj->second}};
stacks[p] = stack;
}
else
{
// found
Stack stack = stacks.at( p );
stack[obj->second->zorder] = obj->second;
stacks[p] = stack;
}
}
}
// find size of ghost
for (auto const& [point, stack] : stacks)
{
for ( auto obj = stack.begin(); obj != stack.end(); ++obj )
{
int x = obj->second->counter->pos().x();
int y = obj->second->counter->pos().y();
QPoint p = QPoint(x, y);
QRect thisRect = QRect(p, obj->second->counter->size());
totalRect = totalRect.united(thisRect);
}
}
// paint ghost
QImage base = QImage (totalRect.size(), QImage::Format_ARGB32_Premultiplied);
base.fill(Qt::transparent);
QPainter *paint = new QPainter(&base);
for (auto const& [point, stack] : stacks)
{
for ( auto obj = stack.begin(); obj != stack.end(); ++obj )
{
// coordinates relative to paint surface
int x = obj->second->counter->pos().x() - totalRect.x();
int y = obj->second->counter->pos().y() - totalRect.y();
paint->drawImage(x, y, obj->second->baseBuffer);
}
}
delete paint;
// make transparent
QImage transparent = QImage (totalRect.size(), QImage::Format_ARGB32_Premultiplied);
transparent.fill(Qt::transparent);
paint = new QPainter(&transparent);
paint->setOpacity(0.5);
paint->drawImage(0, 0, base);
delete paint;
return transparent;
}
Since no data structure holds selected counters, the stacks of selected counters must first be generated.
Then the size of the ghost image must be found, what can be called the ghostRect. This is done by uniting the rects of the individual counters. QRect has a function called united
for this. The ghostRect is the minimum area of all the counters including their margins.
The ghost image is then painted with the images of the individual counters. Finally the whole ghost image is made semi-transparent.
Hoovering over a stack looks like this. The cursor must not move for at least 0,7 seconds.
Two selected stacks are moved. Start position:
Dragging of ghost image:
Drag drop and final position (all counters marked as moved):
Here is a sequence of opening, reordering, unselecting and then moving the selected units.
Open the stack:
Unselect top and bottom counter:
Reorder (swap) the top and bottom counter of the stack:
Reorder (swap) blue French units:
Hoover over new stack:
Move selected units of the stack:
Hoover over the moved stack:
Code found here.
CPLUS_INCLUDE_PATH=/opt/Qt6.5/include;export CPLUS_INCLUDE_PATH
LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu:/opt/Qt6.5/lib;export LD_LIBRARY_PATH
g++ -Wall -o main main.cpp luau.cpp counter.cpp window.cpp frame.cpp overlay.cpp -I/home/me/luau/VM/include -I/home/me/luau/Compiler/include -I/opt/Qt6.5/include/QtWidgets -Wl,--copy-dt-needed-entries -L/opt/Qt6.5/lib -lQt6Core -lQt6Widgets -L/home/me/luau/build/release -lluauvm -lluaucompiler -lluauast -lisocline