Pie menus from feb
This commit is contained in:
parent
6d37639d93
commit
191c85a63f
10 changed files with 292 additions and 31 deletions
doc/scripts
src
|
@ -894,6 +894,18 @@ FIXME
|
|||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>"pie-menu", {tag, value, ...}</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>"radius", radius</dt>
|
||||
<dd>The radius in pixels of the pie menu.</dd>
|
||||
<dt>"file", "filename"</dt>
|
||||
<dd>The image file for the background of the pie menu.</dd>
|
||||
<dt>"mouse-button", "buttonname"</dt>
|
||||
<dd>Which mouse button pops up the pie menu. Can be "right", "middle" or "left".
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>"map-area", {"pos", {x, y}, size, {w, h}}</dt>
|
||||
<dd>FIXME</dd>
|
||||
<dt>"menu-panel", {tag, value}</dt>
|
||||
|
|
|
@ -166,6 +166,7 @@ typedef enum _cursor_states_ {
|
|||
CursorStatePoint, ///< Normal cursor
|
||||
CursorStateSelect, ///< Select position
|
||||
CursorStateRectangle, ///< Rectangle selecting
|
||||
CursorStatePieMenu, ///< Displaying Pie Menu
|
||||
} CursorStates;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
|
|
|
@ -179,6 +179,7 @@ enum _key_modifiers_ {
|
|||
|
||||
/// pressed mouse button flags
|
||||
enum _mouse_buttons_ {
|
||||
NoButton = 0, ///< No button
|
||||
LeftButton = 2, ///< Left button on mouse
|
||||
MiddleButton = 4, ///< Middle button on mouse
|
||||
RightButton = 8, ///< Right button on mouse
|
||||
|
@ -390,6 +391,10 @@ extern void DrawTimer(void);
|
|||
extern void UpdateTimer(void);
|
||||
/// Draw the unit button panel
|
||||
extern void DrawButtonPanel(void);
|
||||
/// Update the status line with hints from the button
|
||||
extern void UpdateStatusLineForButton(const ButtonAction*);
|
||||
/// Draw the Pie Menu
|
||||
extern void DrawPieMenu(void);
|
||||
/// Update the content of the unit button panel
|
||||
extern void UpdateButtonPanel(void);
|
||||
/// Handle button click in button panel area
|
||||
|
|
|
@ -249,6 +249,12 @@ typedef struct _ui_ {
|
|||
int ButtonPanelY; ///< Button panel screen Y position
|
||||
int CommandKeyFont; ///< Command key font
|
||||
|
||||
// Pie Menu
|
||||
GraphicConfig PieMenuBackground; ///< Optional background image for the piemenu
|
||||
enum _mouse_buttons_ PieMouseButton; ///< Which mouse button pops up the piemenu. Deactivate with the NoButton value.
|
||||
int PieX[8]; ///< X position of the pies
|
||||
int PieY[8]; ///< Y position of the pies
|
||||
|
||||
// Map area
|
||||
ViewportMode ViewportMode; ///< Current viewport mode
|
||||
Viewport* MouseViewport; ///< Viewport containing mouse
|
||||
|
|
|
@ -376,6 +376,7 @@ global void UpdateDisplay(void)
|
|||
DrawTimer();
|
||||
}
|
||||
|
||||
DrawPieMenu(); // draw pie menu only if needed
|
||||
DrawMenu(CurrentMenu);
|
||||
|
||||
DrawAnyCursor();
|
||||
|
|
|
@ -220,7 +220,6 @@ global void DrawButtonPanel(void)
|
|||
int i;
|
||||
int v;
|
||||
Player* player;
|
||||
const UnitStats* stats;
|
||||
const ButtonAction* buttons;
|
||||
char buf[8];
|
||||
|
||||
|
@ -351,29 +350,7 @@ global void DrawButtonPanel(void)
|
|||
//
|
||||
if (ButtonAreaUnderCursor == ButtonAreaButton &&
|
||||
ButtonUnderCursor == i && KeyState != KeyStateInput) {
|
||||
SetStatusLine(buttons[i].Hint);
|
||||
// FIXME: Draw costs
|
||||
v = buttons[i].Value;
|
||||
switch (buttons[i].Action) {
|
||||
case ButtonBuild:
|
||||
case ButtonTrain:
|
||||
case ButtonUpgradeTo:
|
||||
// FIXME: store pointer in button table!
|
||||
stats = &UnitTypes[v]->Stats[player->Player];
|
||||
|
||||
SetCosts(0, UnitTypes[v]->Demand, stats->Costs);
|
||||
break;
|
||||
case ButtonResearch:
|
||||
SetCosts(0, 0, Upgrades[v].Costs);
|
||||
break;
|
||||
case ButtonSpellCast:
|
||||
SetCosts(SpellTypeTable[v]->ManaCost, 0, NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
ClearCosts();
|
||||
break;
|
||||
}
|
||||
UpdateStatusLineForButton(&buttons[i]);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -403,6 +380,39 @@ global void DrawButtonPanel(void)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Update the status line with hints from the button
|
||||
**
|
||||
** @param button Button
|
||||
*/
|
||||
global void UpdateStatusLineForButton(const ButtonAction* button)
|
||||
{
|
||||
int v;
|
||||
const UnitStats* stats;
|
||||
|
||||
SetStatusLine(button->Hint);
|
||||
// FIXME: Draw costs
|
||||
v = button->Value;
|
||||
switch (button->Action) {
|
||||
case ButtonBuild:
|
||||
case ButtonTrain:
|
||||
case ButtonUpgradeTo:
|
||||
// FIXME: store pointer in button table!
|
||||
stats = &UnitTypes[v]->Stats[ThisPlayer->Player];
|
||||
SetCosts(0, UnitTypes[v]->Demand, stats->Costs);
|
||||
break;
|
||||
case ButtonResearch:
|
||||
SetCosts(0, 0, Upgrades[v].Costs);
|
||||
break;
|
||||
case ButtonSpellCast:
|
||||
SetCosts(SpellTypeTable[v]->ManaCost, 0, NULL);
|
||||
break;
|
||||
default:
|
||||
ClearCosts();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Functions
|
||||
----------------------------------------------------------------------------*/
|
||||
|
|
|
@ -347,7 +347,7 @@ global const char* IdentOfIcon(const Icon* icon)
|
|||
global void DrawIcon(const Player* player, Icon* icon, int x, int y)
|
||||
{
|
||||
GraphicPlayerPixels(player, icon->Sprite);
|
||||
VideoDraw(icon->Sprite, icon->Index, x, y);
|
||||
VideoDrawClip(icon->Sprite, icon->Index, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
179
src/ui/mouse.cpp
179
src/ui/mouse.cpp
|
@ -30,12 +30,16 @@
|
|||
|
||||
//@{
|
||||
|
||||
#define ICON_SIZE_X (TheUI.ButtonButtons[0].Width)
|
||||
#define ICON_SIZE_Y (TheUI.ButtonButtons[0].Height)
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Includes
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "stratagus.h"
|
||||
#include "tileset.h"
|
||||
|
@ -78,6 +82,7 @@ global enum _cursor_on_ CursorOn = CursorOnUnknown; /// Cursor on field
|
|||
/*----------------------------------------------------------------------------
|
||||
-- Functions
|
||||
----------------------------------------------------------------------------*/
|
||||
local void HandlePieMenuMouseSelection(void);
|
||||
|
||||
/**
|
||||
** Cancel building cursor mode.
|
||||
|
@ -657,6 +662,23 @@ global void UIHandleMouseMove(int x, int y)
|
|||
return;
|
||||
}
|
||||
|
||||
if (CursorState == CursorStatePieMenu && CursorOn == CursorOnMap) {
|
||||
// in the map area
|
||||
// make the piemenu "follow" the mouse
|
||||
if (CursorX - CursorStartX > TheUI.PieX[2]) {
|
||||
CursorStartX = CursorX - TheUI.PieX[2];
|
||||
}
|
||||
if (CursorStartX - CursorX > TheUI.PieX[2]) {
|
||||
CursorStartX = CursorX + TheUI.PieX[2];
|
||||
}
|
||||
if (CursorStartY - CursorY > TheUI.PieY[4]) {
|
||||
CursorStartY = CursorY + TheUI.PieY[4];
|
||||
}
|
||||
if (CursorY - CursorStartY > TheUI.PieY[4]) {
|
||||
CursorStartY = CursorY - TheUI.PieY[4];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Move map.
|
||||
//
|
||||
|
@ -1320,6 +1342,7 @@ local void UISelectStateButtonDown(unsigned button __attribute__((unused)))
|
|||
UpdateButtonPanel();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
** Called if mouse button pressed down.
|
||||
**
|
||||
|
@ -1374,6 +1397,16 @@ global void UIHandleButtonDown(unsigned button)
|
|||
return;
|
||||
}
|
||||
|
||||
if (CursorState == CursorStatePieMenu) {
|
||||
if (CursorOn == CursorOnMap) {
|
||||
HandlePieMenuMouseSelection();
|
||||
} else {
|
||||
// Pie Menu canceled
|
||||
CursorState = CursorStatePoint;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Cursor is on the map area
|
||||
//
|
||||
|
@ -1431,7 +1464,15 @@ global void UIHandleButtonDown(unsigned button)
|
|||
return;
|
||||
}
|
||||
|
||||
if (MouseButtons & LeftButton) { // enter select mode
|
||||
if (MouseButtons & TheUI.PieMouseButton) { // enter pie menu
|
||||
CursorStartX = CursorX;
|
||||
CursorStartY = CursorY;
|
||||
if (NumSelected && Selected[0]->Player == ThisPlayer &&
|
||||
CursorState == CursorStatePoint) {
|
||||
CursorState = CursorStatePieMenu;
|
||||
MustRedraw |= RedrawCursor;
|
||||
}
|
||||
} else if (MouseButtons & LeftButton) { // enter select mode
|
||||
CursorStartX = CursorX;
|
||||
CursorStartY = CursorY;
|
||||
CursorStartScrMapX = CursorStartX - TheUI.MouseViewport->X +
|
||||
|
@ -1458,8 +1499,8 @@ global void UIHandleButtonDown(unsigned button)
|
|||
y = Viewport2MapY(TheUI.MouseViewport, CursorY);
|
||||
|
||||
if (UnitUnderCursor && (unit = UnitOnMapTile(x, y)) &&
|
||||
!UnitUnderCursor->Type->Decoration) {
|
||||
unit->Blink = 4; // if right click on building -- blink
|
||||
!UnitUnderCursor->Type->Decoration) {
|
||||
unit->Blink = 4; // if right click on building -- blink
|
||||
} else { // if not not click on building -- green cross
|
||||
if (ClickMissile) {
|
||||
MakeLocalMissile(MissileTypeByIdent(ClickMissile),
|
||||
|
@ -1525,7 +1566,7 @@ global void UIHandleButtonDown(unsigned button)
|
|||
if (ButtonUnderCursor == 0 && NumSelected == 1) {
|
||||
PlayGameSound(GameSounds.Click.Sound, MaxSampleVolume);
|
||||
ViewportCenterViewpoint(TheUI.SelectedViewport, Selected[0]->X,
|
||||
Selected[0]->Y, Selected[0]->IX + TileSizeX / 2,
|
||||
Selected[0]->Y, Selected[0]->IX + TileSizeX / 2,
|
||||
Selected[0]->IY + TileSizeY / 2);
|
||||
}
|
||||
//
|
||||
|
@ -1559,7 +1600,7 @@ global void UIHandleButtonDown(unsigned button)
|
|||
// clicked on researching button
|
||||
//
|
||||
} else if (ButtonAreaUnderCursor == ButtonAreaResearching) {
|
||||
if (!GameObserve && !GamePaused &&
|
||||
if (!GameObserve && !GamePaused &&
|
||||
PlayersTeamed(ThisPlayer->Player, Selected[0]->Player->Player)) {
|
||||
if (ButtonUnderCursor == 0 && NumSelected == 1) {
|
||||
DebugPrint("Cancel research %s\n" _C_
|
||||
|
@ -1628,6 +1669,18 @@ global void UIHandleButtonUp(unsigned button)
|
|||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Pie Menu
|
||||
//
|
||||
if (CursorState == CursorStatePieMenu) {
|
||||
if (CursorStartX == CursorX && CursorStartY == CursorY) {
|
||||
// no move; wait for a click to select the pie
|
||||
} else {
|
||||
// there was a move, handle the selected button/pie
|
||||
HandlePieMenuMouseSelection();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Menu (F10) button
|
||||
//
|
||||
|
@ -1797,7 +1850,7 @@ global void UIHandleButtonUp(unsigned button)
|
|||
if (Selected[0]->Player == ThisPlayer) {
|
||||
char buf[64];
|
||||
if (Selected[0]->Player->UnitTypesCount[Selected[0]->Type->Slot] > 1) {
|
||||
sprintf(buf, "You have ~<%d~> %ss",
|
||||
sprintf(buf, "You have ~<%d~> %ss",
|
||||
Selected[0]->Player->UnitTypesCount[Selected[0]->Type->Slot],
|
||||
Selected[0]->Type->Name);
|
||||
} else {
|
||||
|
@ -1817,4 +1870,118 @@ global void UIHandleButtonUp(unsigned button)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Get pie menu under the cursor
|
||||
*/
|
||||
local int GetPieUnderCursor(void)
|
||||
{
|
||||
int i;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
x = CursorX - (CursorStartX - ICON_SIZE_X / 2);
|
||||
y = CursorY - (CursorStartY - ICON_SIZE_Y / 2);
|
||||
for (i = 0; i < 8; ++i) {
|
||||
if (x > TheUI.PieX[i] && x < TheUI.PieX[i] + ICON_SIZE_X &&
|
||||
y > TheUI.PieY[i] && y < TheUI.PieY[i] + ICON_SIZE_Y) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1; // no pie under cursor
|
||||
}
|
||||
|
||||
/**
|
||||
** Draw Pie Menu
|
||||
*/
|
||||
global void DrawPieMenu(void)
|
||||
{
|
||||
int i;
|
||||
const ButtonAction* buttons;
|
||||
Viewport* vp;
|
||||
Player* player;
|
||||
char buf[2] = "?";
|
||||
|
||||
if(CursorState != CursorStatePieMenu)
|
||||
return;
|
||||
|
||||
if (!(buttons = CurrentButtons)) { // no buttons
|
||||
CursorState = CursorStatePoint;
|
||||
return;
|
||||
}
|
||||
|
||||
vp = TheUI.SelectedViewport;
|
||||
PushClipping();
|
||||
SetClipping(vp->X, vp->Y, vp->EndX, vp->EndY);
|
||||
|
||||
// Draw background
|
||||
if (TheUI.PieMenuBackground.Graphic) {
|
||||
VideoDrawClip(TheUI.PieMenuBackground.Graphic, 0,
|
||||
CursorStartX - TheUI.PieMenuBackground.Graphic->Width / 2,
|
||||
CursorStartY - TheUI.PieMenuBackground.Graphic->Height / 2);
|
||||
}
|
||||
player = Selected[0]->Player;
|
||||
|
||||
for (i = 0; i < TheUI.NumButtonButtons && i < 8; ++i) {
|
||||
if (buttons[i].Pos != -1) {
|
||||
int x;
|
||||
int y;
|
||||
|
||||
x = CursorStartX - ICON_SIZE_X / 2 + TheUI.PieX[i];
|
||||
y = CursorStartY - ICON_SIZE_Y / 2 + TheUI.PieY[i];
|
||||
// Draw icon
|
||||
DrawIcon(player, buttons[i].Icon.Icon, x, y);
|
||||
|
||||
// Tutorial show command key in icons
|
||||
if (ShowCommandKey) {
|
||||
char* text;
|
||||
|
||||
if (CurrentButtons[i].Key == 27) {
|
||||
text = "ESC";
|
||||
} else {
|
||||
buf[0] = toupper(CurrentButtons[i].Key);
|
||||
text = buf;
|
||||
}
|
||||
VideoDrawText(x + 4, y + 4, GameFont, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PopClipping();
|
||||
|
||||
i = GetPieUnderCursor();
|
||||
if (i != -1 && KeyState != KeyStateInput && buttons[i].Pos!=-1) {
|
||||
UpdateStatusLineForButton(&buttons[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Handle pie menu mouse selection
|
||||
*/
|
||||
local void HandlePieMenuMouseSelection(void)
|
||||
{
|
||||
int pie;
|
||||
|
||||
if (!CurrentButtons) { // no buttons
|
||||
return;
|
||||
}
|
||||
|
||||
pie = GetPieUnderCursor();
|
||||
if (pie != -1) {
|
||||
if (CurrentButtons[pie].Action == ButtonButton) {
|
||||
// there is a submenu => stay in piemenu mode
|
||||
// and recenter the piemenu around the cursor
|
||||
CursorStartX = CursorX;
|
||||
CursorStartY = CursorY;
|
||||
} else {
|
||||
CursorState = CursorStatePoint;
|
||||
}
|
||||
DoButtonButtonClicked(pie);
|
||||
} else {
|
||||
CursorState = CursorStatePoint;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//@}
|
||||
|
|
|
@ -1574,6 +1574,57 @@ local int CclDefineUI(lua_State* l)
|
|||
LuaError(l, "Unsupported tag: %s" _C_ value);
|
||||
}
|
||||
}
|
||||
} else if (!strcmp(value, "piemenu")) {
|
||||
k = 0;
|
||||
if (!lua_istable(l, j + 1)) {
|
||||
lua_pushstring(l, "incorrect argument");
|
||||
lua_error(l);
|
||||
}
|
||||
subargs = luaL_getn(l, j + 1);
|
||||
for (k = 0; k < subargs; ++k) {
|
||||
lua_rawgeti(l, j + 1, k + 1);
|
||||
value = LuaToString(l, -1);
|
||||
lua_pop(l, 1);
|
||||
++k;
|
||||
if (!strcmp(value, "file")) {
|
||||
lua_rawgeti(l, j + 1, k + 1);
|
||||
ui->PieMenuBackground.File = strdup(LuaToString(l, -1));
|
||||
lua_pop(l, 1);
|
||||
} else if (!strcmp(value, "radius")) {
|
||||
// Position of the pies in a piemenu
|
||||
int coeffX[] = { 0, 193, 256, 193, 0, -193, -256, -193};
|
||||
int coeffY[] = { -256, -193, 0, 193, 256, 193, 0, -193};
|
||||
int pie;
|
||||
int radius;
|
||||
|
||||
lua_rawgeti(l, j + 1, k + 1);
|
||||
radius = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
for (pie = 0; pie < 8; ++pie) {
|
||||
ui->PieX[pie]= (coeffX[pie] * radius) >> 8;
|
||||
ui->PieY[pie]= (coeffY[pie] * radius) >> 8;
|
||||
}
|
||||
} else if (!strcmp(value, "mouse-button")) {
|
||||
const char *button;
|
||||
|
||||
lua_rawgeti(l, j + 1, k + 1);
|
||||
button = LuaToString(l, -1);
|
||||
if (!strcmp(button, "right")) {
|
||||
ui->PieMouseButton = RightButton;
|
||||
} else if (!strcmp(button, "middle")) {
|
||||
ui->PieMouseButton = MiddleButton;
|
||||
} else if (!strcmp(button, "left")) {
|
||||
ui->PieMouseButton = LeftButton;
|
||||
} else {
|
||||
ui->PieMouseButton = NoButton;
|
||||
}
|
||||
lua_pop(l, 1);
|
||||
} else {
|
||||
lua_pushfstring(l, "Unsupported tag: %s", value);
|
||||
lua_error(l);
|
||||
}
|
||||
}
|
||||
lua_pop(l, 1);
|
||||
} else if (!strcmp(value, "map-area")) {
|
||||
int w;
|
||||
int h;
|
||||
|
|
|
@ -99,6 +99,7 @@ local void CleanUIGraphics(UI* ui)
|
|||
VideoSafeFree(ui->MenuPanel.Graphic);
|
||||
VideoSafeFree(ui->MinimapPanel.Graphic);
|
||||
VideoSafeFree(ui->StatusLine.Graphic);
|
||||
VideoSafeFree(ui->PieMenuBackground.Graphic);
|
||||
|
||||
menupanel = ui->MenuPanels;
|
||||
while (menupanel) {
|
||||
|
@ -238,6 +239,10 @@ global void LoadUserInterface(void)
|
|||
if (TheUI.ButtonPanel.File) {
|
||||
TheUI.ButtonPanel.Graphic = LoadGraphic(TheUI.ButtonPanel.File);
|
||||
}
|
||||
if (TheUI.PieMenuBackground.File) {
|
||||
TheUI.PieMenuBackground.Graphic =
|
||||
LoadGraphic(TheUI.PieMenuBackground.File);
|
||||
}
|
||||
if (TheUI.MenuPanel.File) {
|
||||
TheUI.MenuPanel.Graphic = LoadGraphic(TheUI.MenuPanel.File);
|
||||
}
|
||||
|
@ -362,6 +367,9 @@ global void CleanUI(UI* ui)
|
|||
// Menu Button
|
||||
free(ui->MenuPanel.File);
|
||||
|
||||
// Pie Menu
|
||||
free(ui->PieMenuBackground.File);
|
||||
|
||||
// Minimap
|
||||
free(ui->MinimapPanel.File);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue