From e7d20cf352688bf717a01f4e6d9e6f497c2bea4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sat, 20 Sep 2025 19:19:34 +0200 Subject: New upstream version 5.3.1Beta2 --- app/bin/toolbar.c | 613 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 613 insertions(+) create mode 100644 app/bin/toolbar.c (limited to 'app/bin/toolbar.c') diff --git a/app/bin/toolbar.c b/app/bin/toolbar.c new file mode 100644 index 0000000..57c3659 --- /dev/null +++ b/app/bin/toolbar.c @@ -0,0 +1,613 @@ +/*****************************************************************//** + * \file toolbar.c + * \brief Toolbar specific functions and data + *********************************************************************/ + +/* XTrackCad - Model Railroad CAD + * Copyright (C) 2005,2023 Dave Bullis, Martin Fischer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "common.h" +#include "custom.h" +#include "fileio.h" +#include "param.h" +#include "track.h" +#include "include/toolbar.h" + +EXPORT void ToolbarLayout(void* unused); + +struct sToolbarState { + int previousGroup; // control variable for change control ops + int layerButton; // number of layer controls shown + wWinPix_t nextX; // drawing position for next control + wWinPix_t rowHeight; // height of row +}; + +// local function prototypes +static void InitializeToolbarDialog(void); +static void ToolbarChange(long changes); +static void ToolbarOk(void* unused); +static void ToolbarButtonPlace(struct sToolbarState* tbState, wIndex_t inx); +static void SaveToolbarConfig(void); + +// toolbar properties +static long toolbarSet; +static wWinPix_t toolbarHeight = 0; + +#define TOOLBARSET_INIT (0xFFFF) +#define TOOLBAR_SECTION "misc" +#define TOOLBAR_VARIABLE "toolbarset" + +#define GROUP_DISTANCE (5) // default distance between button groups +#define GROUP_BIG_DISTANCE (GROUP_DISTANCE * 3) // big gap +#define TOOLBAR_MARGIN (20) // left and right margins of toolbar +#define FIXEDLAYERCONTROLS (2) // the layer groups has two controls that are +// always visible (list and background) + +/* +* Bit handling macros +* these macros do not change the passed values but return the result. +* so if you want to change the value it has to be assigned eg. +* bits = SETBIT(bits, 2); +* in order to set bit 2 of the variable "bits" +* +*/ +#define GETBIT(value, bitpos ) ((value) & (1UL << (bitpos))) +#define ISBITSET(value, bitpos ) (((value)&(1UL < 0); + CHECK(group <= COUNTTOOLBARGROUPS); + + return(ISGROUPVISIBLE(group)); +} + +/** + * Get the current height of the toolbar. + * + * \return + */ + +EXPORT wWinPix_t +ToolbarGetHeight(void) +{ + return(toolbarHeight); +} + +/** + * . + */ + +EXPORT void +ToolbarSetHeight(wWinPix_t newHeight) +{ + toolbarHeight = newHeight; +} + +/** + * Buttons are visible when the command is enabled or when additional + * layer buttons need to be shown. + * + * \param inx + */ + +bool +IsButtonVisible(int group, long mode, long options, long layerButtons) +{ + if (group == BG_LAYER) { + if (layerButtons < layerCount+FIXEDLAYERCONTROLS) { + return true; + } else { + return false; + } + } + return(IsCommandEnabled(mode, options)); +} + +/** + * Calculate the position and visibility of a button and display it. + * + * \param inx index into button list + */ + +static void ToolbarButtonPlace(struct sToolbarState *tbState, wIndex_t inx) +{ + wWinPix_t w, h, offset; + wWinPix_t width; + wWinPix_t gap = GROUP_DISTANCE; + int currentGroup = buttonList[inx].group; + + wWinGetSize(mainW, &width, &h); + + if (buttonList[inx].control) { + if (tbState->rowHeight <= 0) { + tbState->rowHeight = wControlGetHeight(buttonList[inx].control); + toolbarHeight = tbState->rowHeight + 5; + } + + if (currentGroup != tbState->previousGroup) { + for (int i = 0; i < COUNTTOOLBARGROUPS; i++) { + if (allToolbarGroups[i].group == currentGroup && + allToolbarGroups[i].biggap) { + gap = GROUP_BIG_DISTANCE; + } + } + } + + if ((ISGROUPVISIBLE(currentGroup)) && + IsButtonVisible(currentGroup, programMode, + buttonList[inx].options, tbState->layerButton )) { + if (currentGroup != tbState->previousGroup) { + tbState->nextX += gap; + tbState->previousGroup = currentGroup; + } + w = wControlGetWidth(buttonList[inx].control); + h = wControlGetHeight(buttonList[inx].control); + if (h < tbState->rowHeight) { + offset = (h - tbState->rowHeight) / 2; + h = tbState->rowHeight; //Uniform + } else { + offset = 0; + } + if (inx < buttonCnt - 1 && + (buttonList[inx + 1].options & IC_ABUT)) { + w += wControlGetWidth(buttonList[inx + 1].control); + } + if (tbState->nextX + w > width - TOOLBAR_MARGIN) { + tbState->nextX = 5; + toolbarHeight += h + 5; + } + if ((currentGroup == BG_LAYER) && + tbState->layerButton >= FIXEDLAYERCONTROLS && + GetLayerHidden(tbState->layerButton - FIXEDLAYERCONTROLS)) { + wControlShow(buttonList[inx].control, FALSE); + tbState->layerButton++; + } else { + wWinPix_t newX = tbState->nextX; + wWinPix_t newY = toolbarHeight - (h + 5 + offset); + + // count number of shown layer buttons + if (currentGroup == BG_LAYER) { + tbState->layerButton++; + } + if ((newX != buttonList[inx].x) || (newY != buttonList[inx].y)) { + wControlShow(buttonList[inx].control, FALSE); + + wControlSetPos(buttonList[inx].control, newX, + newY); + } + buttonList[inx].x = newX; + buttonList[inx].y = newY; + tbState->nextX += wControlGetWidth(buttonList[inx].control); + wControlShow(buttonList[inx].control, TRUE); + } + } else { + wControlShow(buttonList[inx].control, FALSE); + } + } +} + +EXPORT void ToolbarLayout(void* data) +{ + int inx; + struct sToolbarState state = { + .previousGroup = 0, + .nextX = 0, + .layerButton = 0, + .rowHeight = 0, + }; + + for (inx = 0; inx < buttonCnt; inx++) { + ToolbarButtonPlace(&state, inx); + } + + if (ISBITSET(toolbarSet, BG_HOTBAR)) { + LayoutHotBar(data); + } else { + HideHotBar(); + } +} + +/** + * Set the 'pressed' state of a toolbar button. + * + * \param button index into button list + * \param busy desired button state + */ + +EXPORT void ToolbarButtonBusy(wIndex_t button, wBool_t busy) +{ + wButtonSetBusy((wButton_p)buttonList[button].control, + busy); +} + +/** + * Set state of a toolbar button . + * + * \param button index into button list + * \param enable desired state, FALSE if disabled, TRUE if enabled + */ + +EXPORT void ToolbarButtonEnable(wIndex_t button, wBool_t enable) +{ + wControlActive(buttonList[button].control, + enable); +} + +/** + * Enable toolbar buttons that depend on selected track. + * + * \param selected true if any track is selected + */ + +EXPORT void ToolbarButtonEnableIfSelect(bool selected) +{ + for (int inx = 0; inx < buttonCnt; inx++) { + if (buttonList[inx].cmdInx < 0 + && (buttonList[inx].options & IC_SELECTED)) { + ToolbarButtonEnable(inx, selected ); + } + } +} + +/** + * Place a control onto the toolbar. The control is added to the toolbar + * control list and initially hidden. Placement and visibility is controlled + * by ToolbarButtonPlace() + * + * \param control the control to add + * \param options control options + */ + +EXPORT void ToolbarControlAdd(wControl_p control, long options, int cmdGroup) +{ + CHECK(buttonCnt < BUTTON_MAX - 1); + buttonList[buttonCnt].enabled = TRUE; + buttonList[buttonCnt].options = options; + buttonList[buttonCnt].group = cmdGroup; + buttonList[buttonCnt].x = 0; + buttonList[buttonCnt].y = 0; + buttonList[buttonCnt].control = control; + buttonList[buttonCnt].cmdInx = -1; + wControlShow(control, FALSE); + buttonCnt++; +} + +/** + * Link a command to a specific toolbar button. + * + * \param button the button + * \param command command to activate when button is pressed + * \return + */ + +EXPORT void ToolbarButtonCommandLink(wIndex_t button, int command) +{ + if (button >= 0 && buttonList[button].cmdInx == -1) { + // set button back-link + buttonList[button].cmdInx = commandCnt; + } +} + +/** + * Update the toolbar button for selected command eg. circle vs. filled + * circle. + * + * \param button toolbar button + * \param command current command + * \param icon new icon + * \param helpKey new help key + * \param context new command context + */ + +EXPORT void ToolbarUpdateButton(wIndex_t button, wIndex_t command, + char * icon, + const char * helpKey, + void * context) +{ + if (buttonList[button].cmdInx != command) { + wButtonSetLabel((wButton_p) buttonList[button].control,icon); + wControlSetHelp(buttonList[button].control, + GetBalloonHelpStr(helpKey)); + wControlSetContext(buttonList[button].control, + context); + buttonList[button].cmdInx = command; + } +} + +/*--------------------------------------------------------------------*/ + +/** + * Handle simulated button press during playbook. + * + * \param buttInx selected button + */ +EXPORT void PlaybackButtonMouse(wIndex_t buttInx) +{ + wWinPix_t cmdX, cmdY; + coOrd pos; + + if (buttInx < 0 || buttInx >= buttonCnt) { + return; + } + if (buttonList[buttInx].control == NULL) { + return; + } + cmdX = buttonList[buttInx].x + 17; + cmdY = toolbarHeight - (buttonList[buttInx].y + 17) + + (wWinPix_t)(mainD.size.y / mainD.scale * mainD.dpi) + 30; + + mainD.Pix2CoOrd(&mainD, cmdX, cmdY, &pos); + MovePlaybackCursor(&mainD, pos, TRUE, buttonList[buttInx].control); + if (playbackTimer == 0) { + wButtonSetBusy((wButton_p)buttonList[buttInx].control, TRUE); + wFlush(); + wPause(500); + wButtonSetBusy((wButton_p)buttonList[buttInx].control, FALSE); + wFlush(); + } +} + +/** + * Handle cursor positioning for toolbar buttons during playback . + * + * \param buttonInx + */ + +EXPORT void ToolbarButtonPlayback(wIndex_t buttonInx) +{ + wWinPix_t cmdX, cmdY; + coOrd pos; + + cmdX = buttonList[buttonInx].x + 17; + cmdY = toolbarHeight - (buttonList[buttonInx].y + 17) + + (wWinPix_t)(mainD.size.y / mainD.scale * mainD.dpi) + 30; + mainD.Pix2CoOrd(&mainD, cmdX, cmdY, &pos); + MovePlaybackCursor(&mainD, pos, TRUE, buttonList[buttonInx].control); +} + +/** + * Save the toolbar setting to the configuration file. + * + */ + +static void +SaveToolbarConfig(void) +{ + wPrefSetInteger(TOOLBAR_SECTION, TOOLBAR_VARIABLE, toolbarSet); + if (recordF) + fprintf(recordF, "PARAMETER %s %s %ld", TOOLBAR_SECTION, + TOOLBAR_VARIABLE, toolbarSet); + +} + +/** + * Get the preferences for the toolbar from the configuration file. + * Bits unused are cleared just to be sure; + * + */ + +EXPORT void +ToolbarLoadConfig(void) +{ + unsigned long maxToolbarSet = (1 << COUNTTOOLBARGROUPS) - 1; + long toolbarSetIni; + + wPrefGetInteger(TOOLBAR_SECTION, TOOLBAR_VARIABLE, &toolbarSetIni, + TOOLBARSET_INIT); + + toolbarSet = (unsigned long)toolbarSetIni & maxToolbarSet; + + // unused but saved to stay compatible + wPrefSetInteger(TOOLBAR_SECTION, "max-toolbarset", maxToolbarSet); + + if (recordF) + fprintf(recordF, "PARAMETER %s %s %lX -> %lX", TOOLBAR_SECTION, + TOOLBAR_VARIABLE, toolbarSetIni, toolbarSet); +} + +/** + * Initialize toolbar functions. + * + */ + +EXPORT void InitToolbar(void) +{ + RegisterChangeNotification(ToolbarChange); + + ToolbarLoadConfig(); +} -- cgit v1.2.3