Изменение интерфейса скриптами

Автор темы #1
Дата рег
29 Июн 2014
Сообщения
38
Симпатии
2
Привет всем.
Как изменить состояние элемента интерфейса в произвольный момент времени? Например, как сделать, чтобы картинка на элементе менялась, если сломана нога? В самом начале, в client_main, создал все необходимые элементы, с картинками, расположением и прочими параметрами по умолчанию. Как изменить, например, статус элемента (нажат/не нажат: SwitchEnabled или то, что меняется функцией Switch()) или его картинку (например, лампочка не горела, а, когда нога стала сломанной, загорелась)?

Когда я меняю состояние кнопки при её создании, всё работает. Можно сделать все кнопки всегда зажатыми. Но менять его по щелчку, например, не получается (если нужно, чтобы кнопка работала как чекбокс - нажималась и сохраняла положение). Просмотр radio.fos и модуля про регистрацию с включённым 3d не дал результатов. Много часов пробовал разными способами это осуществить, но не преуспел.

Прошу помощи
 
Дата рег
17 Сен 2014
Сообщения
132
Симпатии
18
Leprechaun, делаешь переменную int switch = 0;

Когда клиент жмакает кнопку - switch = 1.

А гду рисуется картинка ставишь условие:
if(switch==1)
{рисовать картинку #1}
else
{рисовать картинку #2}
 
Автор темы #3
Дата рег
29 Июн 2014
Сообщения
38
Симпатии
2
Leprechaun, делаешь переменную int switch = 0;

Когда клиент жмакает кнопку - switch = 1.

А гду рисуется картинка ставишь условие:
if(switch==1)
{рисовать картинку #1}
else
{рисовать картинку #2}
А где она рисуется? Там, где создаётся кнопка, или дополнительно нужно рисовать?
 
Автор темы #4
Дата рег
29 Июн 2014
Сообщения
38
Симпатии
2
Есть смысл рисовать интерфейс в client_main.fos, где рисуются слои интерфейса? Например, как таймауты и прочее? Это не будет уменьшать производительность?
 
Дата рег
17 Сен 2014
Сообщения
132
Симпатии
18
Только там и рисуется. Даже разбивка по слоям в скрипте предусмотрена.
 
Дата рег
22 Мар 2014
Сообщения
166
Симпатии
17
Вот тебе на размышление
Код:
uint Filters=31;
#define TileSwitch				 ( 0x00000080 )
 
 
 
class ButtonTileSwitch : IGUIElementCallbackInit, IGUIElementCallbackMouseClick
{
	IGUIElementOpt@ self;
	void OnInit()
	{
		@self=GUI_GetElementOptions();
		if (__ShowTile) self.Switch(!FLAG(Filters,self.GetTag()));
		if (!__ShowTile) self.Switch(FLAG(Filters,self.GetTag()));
	}
 
	void OnMouseClick( int click )
	{
		if( click == MOUSE_CLICK_LEFT )
		{
			if(__ShowTile )
				{
					__ShowTile =false;
					self.Switch(FLAG(Filters,self.GetTag()));
				}
			else
				{
					__ShowTile  =true;
					self.Switch(!FLAG(Filters,self.GetTag()));
				}
		}
	}
}
 
 
 
void AddSwitch8(string key, uint flag, ButtonTileSwitch swch8, int screen)
{
  int[] coords=GetIfaceCoords(key);
  GUI_AddScreenElement(screen, GetIfaceIniStr("MoptOptionSwitchOn"), coords[0],   coords[1])
  .DownPic(GetIfaceIniStr("MoptOptionSwitchOff"))
  .SetTag(flag)
  .CallbackInit(swch8)
  .CallbackMouseClick(swch8)
  .Sound("BUTIN2.ACM")
  .ToCenter(true);
}
 
 
 
void GuiInit ()
{
ButtonTileSwitch swch8;
AddSwitch8("MoptOptionsTileSwitch", TileSwitch, swch8, CLIENT_SCREEN_NEWOPTIONS);
}
 
Автор темы #8
Дата рег
29 Июн 2014
Сообщения
38
Симпатии
2
Medvedev, попробовал создавать кнопки там, где рисуется интерфейс. Но это приводит к тому, что клиент начинает потихоньку отжирать память. Был запущен примерно в течение 10 минут - стал жрать 200 Мб. Видимо, потому, что всё время рисуются новые и новые кнопки, у которых есть картинки. Сделал иначе - создал кнопки только в самом начале. Всё работает нормально, кнопки нажимаются и память не отжирают. В слоях интерфейса у меня рисуются таймауты и ещё всякое, что требует постоянного обновления и перерисовки.

Ametist, спасибо за код, поразмыслил, улучшил свой. Не понял только, как работает
Код:
uint Filters=31;
#define TileSwitch  ( 0x00000080 )
Очень удобно с GetTag и SetTag. Но это не привело к решению задачи. Мой код изначально делал примерно то же самое. Суть в чём. Когда я нажимаю на кнопку, она выполняет действия, которые указаны в OnClick, и становится зажата. Назад она не "отжимается". А нужно, чтобы из группы кнопок нажата могла быть только одна. Как автоприцеливание на TlaMk2.

Как получить доступ к уже созданному элементу? Как к компоненту, например, по имени или по какому-то идентификатору. Вот, создал я несколько кнопок. А, при выполнении какого-то условия мне нужно их автоматически нажать (без нажатия мышкой), без того, чтобы создавать новые кнопки. Или, к примеру, изменить картинку (чтобы сделать заполняющуюся шкалу, к примеру). Как можно найти элемент, который уже был создан, и изменить его в run-time (если можно так назвать)?
 
Автор темы #10
Дата рег
29 Июн 2014
Сообщения
38
Симпатии
2
Medvedev, вот:
В самом начале, после всех include объявляется класс, который обрабатывает нажатия:
Код:
class ifaceButton : IGUIElementCallbackInit, IGUIElementCallbackMouseClick
{
IGUIElementOpt@ self;
void OnInit()
{
@self=GUI_GetElementOptions();
if( self.GetTag() == 11 ) renderExtraSlot();
}
 
void OnMouseClick( int click )
{
if( click == MOUSE_CLICK_LEFT )
{
if( self.GetTag()<=8 )
{
__Aim = self.GetTag();
self.Switch(true);
}
else if( self.GetTag() == 10 )
{
Message("Фракции только за донат");
}
else if( self.GetTag() == 11 )
{
Message("Доп. слот только за донат");
}
}
}
 
}
Сразу за ним функция, которая добавляет кнопку, вытаскивая параметры из ini:
Код:
void AddSwitch(string keyX, string keyY, string keySpr, string keyDownSpr, ifaceButton clickInit, int Code)
{
GUI_AddScreenElement(CLIENT_MAIN_SCREEN_GAME, keySpr != "" ? GetIfaceIniStr(keySpr) : null, GetIniValue(keyX, 0), GetIniValue(keyY, 0))
.DownPic(GetIfaceIniStr(keyDownSpr))
.CallbackInit(clickInit)
.SetTag(Code)
.CallbackMouseClick(clickInit);
}
А также - функция, которая делает много кнопок, которые нужны. Их будет больше, просто сейчас пока столько:
Код:
void RenderAdditionalIface()
{
/*Tags:
1 - 8: auto-aim. Tag == __Aim
10: factions button
11: additional slot
*/
ifaceButton clickInit;
//factions button
AddSwitch("FractionButtonX", "FractionButtonY", "", "FractionButtonDown", clickInit, 10);
//extra slot
AddSwitch("ExtraSlotX", "ExtraSlotY", "", "ExtraSlotDn", clickInit, 11);
//auto-aim
AddSwitch("aimEyeX", "aimEyeY", "aimEye", "aimEyeDn", clickInit, HIT_LOCATION_EYES);
AddSwitch("aimTorsoX", "aimTorsoY", "aimTorso", "aimTorsoDn", clickInit, HIT_LOCATION_TORSO);
AddSwitch("aimGroinX", "aimGroinY", "aimGroin", "aimGroinDn", clickInit, HIT_LOCATION_GROIN);
AddSwitch("aimLArmX", "aimLArmY", "aimLArm", "aimLArmDn", clickInit, HIT_LOCATION_LEFT_ARM);
AddSwitch("aimRArmX", "aimRArmY", "aimRArm", "aimRArmDn", clickInit, HIT_LOCATION_RIGHT_ARM);
AddSwitch("aimLLegX", "aimLLegY", "aimLLeg", "aimLLegDn", clickInit, HIT_LOCATION_LEFT_LEG);
AddSwitch("aimRLegX", "aimRLegY", "aimRLeg", "aimRLegDn", clickInit, HIT_LOCATION_RIGHT_LEG);
AddSwitch("aimHeadX", "aimHeadY", "aimHead", "aimHeadDn", clickInit, HIT_LOCATION_HEAD);
}
Далее, при старте клиентского скрипта, в конце функции bool start():
Код:
<.. тело bool start ..>
	Load3dFile( "VbMaleWiry.fo3d", PT_ART_CRITTERS );
	Load3dFile( "VbMaleSkeleton.fo3d", PT_ART_CRITTERS );
	#endif
 
RenderAdditionalIface();
	return true;
}
В объекте IGUIElementOpt есть переменная int Tag.
int GetTag() - возвращает значение Tag
IGUIElementOpt@ SetTag( int tagValue ) - устанавливает Tag.

Есть глобальная переменная __Aim, в которую заносится номер части тела, куда нужно автоматически целиться. Для кнопок автоприцеливания Tag равен __Aim, в пределах от 1 до 8 (тут могут быть баги, потом протестирую, пока всё работает). При обработке нажатия __Aim просто устанавливается равным Tag объекта.

Когда я нажимаю на кнопку автоприцеливания, она загорается (происходит Switch(true) ), и такой остаётся. Сейчас в коде нет ничего, что возвращало бы на место другие нажатые кнопки (то есть, делало так:
Код:
self.Switch( __Aim == self.GetTag() ? true : false);
Пытался делать это, находя элементы по Tag - кнопки не возвращаются, только систему грузит (при перерисовке проверялись все элементы основного экрана на предмет Tag != __Aim и, если они не были равны, кнопки делали Switch(false) ).
Пытался делать это при инициализации кнопки - кнопки не возвращаются.
Пытался делать это при нажатии на кнопку - не получилось, не знаю, как быстро найти элемент на экране.

Собственно, вот.
Не пинайте сильно за плохой код, это просто моё хобби. По профессии не программист даже близко.
 
Автор темы #11
Дата рег
29 Июн 2014
Сообщения
38
Симпатии
2
Решил проблему. Может быть, не совсем изящно (т.к. заметно переключение, лампочки гаснут не сразу), но всё же.
В модуле client_gui добавил в конце функции void Draw( int screenX, int screenY ) класса class GUIElement : IGUIElementOpt, вот такой код:
Код:
 if( __Aim != GetTag() ) Switch(false);
Теперь всё хорошо. Можно сделать чуть иначе, добавив в сам класс переменную, и получив из коробки кнопки с возможностью группировки как radio button.

Максимально чертовское спасибо всем, кто помог!