summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/newview/llchiclet.cpp178
-rw-r--r--indra/newview/llchiclet.h22
-rw-r--r--indra/newview/skins/default/xui/en/widgets/chiclet_im_adhoc.xml41
-rw-r--r--indra/newview/skins/default/xui/en/widgets/chiclet_im_group.xml42
-rw-r--r--indra/newview/skins/default/xui/en/widgets/chiclet_im_p2p.xml41
-rw-r--r--indra/newview/skins/default/xui/en/widgets/chiclet_offer.xml22
-rw-r--r--indra/newview/skins/default/xui/en/widgets/chiclet_script.xml32
7 files changed, 232 insertions, 146 deletions
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 660018530f..c97d1254da 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -64,17 +64,10 @@ static LLDefaultChildRegistry::Register<LLAdHocChiclet> t5("chiclet_im_adhoc");
static LLDefaultChildRegistry::Register<LLScriptChiclet> t6("chiclet_script");
static LLDefaultChildRegistry::Register<LLInvOfferChiclet> t7("chiclet_offer");
-static const LLRect CHICLET_RECT(0, 25, 25, 0);
-static const LLRect CHICLET_ICON_RECT(0, 22, 22, 0);
-static const LLRect VOICE_INDICATOR_RECT(50, 25, 70, 0);
-static const LLRect COUNTER_RECT(25, 25, 50, 0);
-static const S32 OVERLAY_ICON_SHIFT = 2; // used for shifting of an overlay icon for new massages in a chiclet
static const S32 SCROLL_BUTTON_PAD = 5;
// static
const S32 LLChicletPanel::s_scroll_ratio = 10;
-const S32 LLChicletNotificationCounterCtrl::MAX_DISPLAYED_COUNT = 99;
-
boost::signals2::signal<LLChiclet* (const LLUUID&),
LLIMChiclet::CollectChicletCombiner<std::list<LLChiclet*> > >
@@ -391,9 +384,9 @@ void LLNotificationChiclet::createMenu()
//////////////////////////////////////////////////////////////////////////
LLChiclet::Params::Params()
- : show_counter("show_counter")
+ : show_counter("show_counter", true)
+ , enable_counter("enable_counter", false)
{
- show_counter = true;
}
LLChiclet::LLChiclet(const Params& p)
@@ -451,26 +444,12 @@ void LLChiclet::setValue(const LLSD& value)
LLIMChiclet::LLIMChiclet(const LLIMChiclet::Params& p)
: LLChiclet(p)
, mShowSpeaker(false)
+, mDefaultWidth(p.rect().getWidth())
, mNewMessagesIcon(NULL)
, mSpeakerCtrl(NULL)
, mCounterCtrl(NULL)
{
- // initialize an overlay icon for new messages
- LLIconCtrl::Params icon_params;
- icon_params.visible = false;
- icon_params.image = LLUI::getUIImage(p.new_messages_icon_name);
- mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(icon_params);
- addChild(mNewMessagesIcon);
-
- // adjust size and position of an icon
- LLRect chiclet_rect = p.rect;
- LLRect overlay_icon_rect = LLRect(chiclet_rect.getWidth()/2, chiclet_rect.getHeight(), chiclet_rect.getWidth(), chiclet_rect.getHeight()/2);
- mNewMessagesIcon->setRect(overlay_icon_rect);
-
- // shift an icon a little bit to the right and up corner of a chiclet
- overlay_icon_rect.translate(OVERLAY_ICON_SHIFT, OVERLAY_ICON_SHIFT);
-
- enableCounterControl(false);
+ enableCounterControl(p.enable_counter);
}
void LLIMChiclet::setShowSpeaker(bool show)
@@ -516,15 +495,15 @@ void LLIMChiclet::setRequiredWidth()
{
bool show_speaker = getShowSpeaker();
bool show_counter = getShowCounter();
- S32 required_width = CHICLET_RECT.getWidth();
+ S32 required_width = mDefaultWidth;
if (show_counter)
{
- required_width += COUNTER_RECT.getWidth();
+ required_width += mCounterCtrl->getRect().getWidth();
}
if (show_speaker)
{
- required_width += VOICE_INDICATOR_RECT.getWidth();
+ required_width += mSpeakerCtrl->getRect().getWidth();
}
reshape(required_width, getRect().getHeight());
@@ -536,14 +515,17 @@ void LLIMChiclet::toggleSpeakerControl()
{
if(getShowSpeaker())
{
+ // move speaker to the right of chiclet icon
+ LLRect speaker_rc = mSpeakerCtrl->getRect();
+ speaker_rc.setLeftTopAndSize(mDefaultWidth, speaker_rc.mTop, speaker_rc.getWidth(), speaker_rc.getHeight());
+ mSpeakerCtrl->setRect(speaker_rc);
+
if(getShowCounter())
{
- mSpeakerCtrl->setRect(VOICE_INDICATOR_RECT);
- }
- else
- {
- mSpeakerCtrl->setRect(COUNTER_RECT);
+ // move speaker to the right of counter
+ mSpeakerCtrl->translate(mCounterCtrl->getRect().getWidth(), 0);
}
+
initSpeakerControl();
}
@@ -644,36 +626,9 @@ LLIMP2PChiclet::Params::Params()
: avatar_icon("avatar_icon")
, unread_notifications("unread_notifications")
, speaker("speaker")
+, new_message_icon("new_message_icon")
, show_speaker("show_speaker")
{
- // *TODO Vadim: Get rid of hardcoded values.
- rect(CHICLET_RECT);
-
- avatar_icon.name("avatar_icon");
- avatar_icon.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
-
- // *NOTE dzaporozhan
- // Changed icon height from 25 to 24 to fix ticket EXT-794.
- // In some cases(after changing UI scale) 25 pixel height icon was
- // drawn incorrectly, i'm not sure why.
- avatar_icon.rect(CHICLET_ICON_RECT);
- avatar_icon.mouse_opaque(false);
-
- unread_notifications.name("unread");
- unread_notifications.font(LLFontGL::getFontSansSerif());
- unread_notifications.font_halign(LLFontGL::HCENTER);
- unread_notifications.v_pad(5);
- unread_notifications.text_color(LLColor4::white);
- unread_notifications.mouse_opaque(false);
- unread_notifications.rect(COUNTER_RECT);
- unread_notifications.visible(false);
-
- speaker.name("speaker");
- speaker.rect(VOICE_INDICATOR_RECT);
- speaker.auto_update(true);
- speaker.draw_border(false);
-
- show_speaker = false;
}
LLIMP2PChiclet::LLIMP2PChiclet(const Params& p)
@@ -681,6 +636,10 @@ LLIMP2PChiclet::LLIMP2PChiclet(const Params& p)
, mChicletIconCtrl(NULL)
, mPopupMenu(NULL)
{
+ LLIconCtrl::Params new_msg_params = p.new_message_icon;
+ mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params);
+ addChild(mNewMessagesIcon);
+
LLChicletAvatarIconCtrl::Params avatar_params = p.avatar_icon;
mChicletIconCtrl = LLUICtrlFactory::create<LLChicletAvatarIconCtrl>(avatar_params);
addChild(mChicletIconCtrl);
@@ -698,10 +657,6 @@ LLIMP2PChiclet::LLIMP2PChiclet(const Params& p)
sendChildToFront(mNewMessagesIcon);
setShowSpeaker(p.show_speaker);
-
- //since mShowSpeaker initialized with false
- //setShowSpeaker(false) will not hide mSpeakerCtrl
- mSpeakerCtrl->setVisible(getShowSpeaker());
}
void LLIMP2PChiclet::initSpeakerControl()
@@ -797,38 +752,10 @@ LLAdHocChiclet::Params::Params()
: avatar_icon("avatar_icon")
, unread_notifications("unread_notifications")
, speaker("speaker")
+, new_message_icon("new_message_icon")
, show_speaker("show_speaker")
, avatar_icon_color("avatar_icon_color", LLColor4::green)
{
- // *TODO Vadim: Get rid of hardcoded values.
- rect(CHICLET_RECT);
-
- avatar_icon.name("avatar_icon");
- avatar_icon.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
-
- // *NOTE dzaporozhan
- // Changed icon height from 25 to 24 to fix ticket EXT-794.
- // In some cases(after changing UI scale) 25 pixel height icon was
- // drawn incorrectly, i'm not sure why.
- avatar_icon.rect(CHICLET_ICON_RECT);
- avatar_icon.mouse_opaque(false);
-
- unread_notifications.name("unread");
- unread_notifications.font(LLFontGL::getFontSansSerif());
- unread_notifications.font_halign(LLFontGL::HCENTER);
- unread_notifications.v_pad(5);
- unread_notifications.text_color(LLColor4::white);
- unread_notifications.mouse_opaque(false);
- unread_notifications.rect(COUNTER_RECT);
- unread_notifications.visible(false);
-
-
- speaker.name("speaker");
- speaker.rect(VOICE_INDICATOR_RECT);
- speaker.auto_update(true);
- speaker.draw_border(false);
-
- show_speaker = false;
}
LLAdHocChiclet::LLAdHocChiclet(const Params& p)
@@ -836,6 +763,10 @@ LLAdHocChiclet::LLAdHocChiclet(const Params& p)
, mChicletIconCtrl(NULL)
, mPopupMenu(NULL)
{
+ LLIconCtrl::Params new_msg_params = p.new_message_icon;
+ mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params);
+ addChild(mNewMessagesIcon);
+
LLChicletAvatarIconCtrl::Params avatar_params = p.avatar_icon;
mChicletIconCtrl = LLUICtrlFactory::create<LLChicletAvatarIconCtrl>(avatar_params);
//Make the avatar modified
@@ -948,32 +879,9 @@ LLIMGroupChiclet::Params::Params()
: group_icon("group_icon")
, unread_notifications("unread_notifications")
, speaker("speaker")
+, new_message_icon("new_message_icon")
, show_speaker("show_speaker")
{
- rect(CHICLET_RECT);
-
- group_icon.name("group_icon");
-
- // *NOTE dzaporozhan
- // Changed icon height from 25 to 24 to fix ticket EXT-794.
- // In some cases(after changing UI scale) 25 pixel height icon was
- // drawn incorrectly, i'm not sure why.
- group_icon.rect(CHICLET_ICON_RECT);
-
- unread_notifications.name("unread");
- unread_notifications.font(LLFontGL::getFontSansSerif());
- unread_notifications.font_halign(LLFontGL::HCENTER);
- unread_notifications.v_pad(5);
- unread_notifications.text_color(LLColor4::white);
- unread_notifications.rect(COUNTER_RECT);
- unread_notifications.visible(false);
-
- speaker.name("speaker");
- speaker.rect(VOICE_INDICATOR_RECT);
- speaker.auto_update(true);
- speaker.draw_border(false);
-
- show_speaker = false;
}
LLIMGroupChiclet::LLIMGroupChiclet(const Params& p)
@@ -982,6 +890,10 @@ LLIMGroupChiclet::LLIMGroupChiclet(const Params& p)
, mChicletIconCtrl(NULL)
, mPopupMenu(NULL)
{
+ LLIconCtrl::Params new_msg_params = p.new_message_icon;
+ mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params);
+ addChild(mNewMessagesIcon);
+
LLChicletGroupIconCtrl::Params avatar_params = p.group_icon;
mChicletIconCtrl = LLUICtrlFactory::create<LLChicletGroupIconCtrl>(avatar_params);
addChild(mChicletIconCtrl);
@@ -1754,7 +1666,7 @@ S32 LLChicletPanel::getTotalUnreadIMCount()
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
LLChicletNotificationCounterCtrl::Params::Params()
-: max_displayed_count("max_displayed_count", MAX_DISPLAYED_COUNT)
+: max_displayed_count("max_displayed_count", 99)
{
}
@@ -1831,6 +1743,7 @@ LLChicletGroupIconCtrl::LLChicletGroupIconCtrl(const Params& p)
: LLIconCtrl(p)
, mDefaultIcon(p.default_icon)
{
+ setValue(LLUUID::null);
}
void LLChicletGroupIconCtrl::setValue(const LLSD& value )
@@ -1882,20 +1795,23 @@ LLChicletSpeakerCtrl::LLChicletSpeakerCtrl(const Params&p)
LLScriptChiclet::Params::Params()
: icon("icon")
+ , new_message_icon("new_message_icon")
{
- // *TODO Vadim: Get rid of hardcoded values.
- rect(CHICLET_RECT);
- icon.rect(CHICLET_ICON_RECT);
}
LLScriptChiclet::LLScriptChiclet(const Params&p)
: LLIMChiclet(p)
, mChicletIconCtrl(NULL)
{
+ LLIconCtrl::Params new_msg_params = p.new_message_icon;
+ mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params);
+ addChild(mNewMessagesIcon);
+
LLIconCtrl::Params icon_params = p.icon;
mChicletIconCtrl = LLUICtrlFactory::create<LLIconCtrl>(icon_params);
- // Let "new message" icon be on top, else it will be hidden behind chiclet icon.
- addChildInBack(mChicletIconCtrl);
+ addChild(mChicletIconCtrl);
+
+ sendChildToFront(mNewMessagesIcon);
}
void LLScriptChiclet::setSessionId(const LLUUID& session_id)
@@ -1934,20 +1850,24 @@ BOOL LLScriptChiclet::handleMouseDown(S32 x, S32 y, MASK mask)
static const std::string INVENTORY_USER_OFFER ("UserGiveItem");
LLInvOfferChiclet::Params::Params()
+ : icon("icon")
+ , new_message_icon("new_message_icon")
{
- // *TODO Vadim: Get rid of hardcoded values.
- rect(CHICLET_RECT);
- icon.rect(CHICLET_ICON_RECT);
}
LLInvOfferChiclet::LLInvOfferChiclet(const Params&p)
: LLIMChiclet(p)
, mChicletIconCtrl(NULL)
{
+ LLIconCtrl::Params new_msg_params = p.new_message_icon;
+ mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params);
+ addChild(mNewMessagesIcon);
+
LLChicletInvOfferIconCtrl::Params icon_params = p.icon;
mChicletIconCtrl = LLUICtrlFactory::create<LLChicletInvOfferIconCtrl>(icon_params);
- // Let "new message" icon be on top, else it will be hidden behind chiclet icon.
- addChildInBack(mChicletIconCtrl);
+ addChild(mChicletIconCtrl);
+
+ sendChildToFront(mNewMessagesIcon);
}
void LLInvOfferChiclet::setSessionId(const LLUUID& session_id)
diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h
index 8c797ef98f..bb2cf3a8de 100644
--- a/indra/newview/llchiclet.h
+++ b/indra/newview/llchiclet.h
@@ -52,8 +52,6 @@ class LLChicletNotificationCounterCtrl : public LLTextBox
{
public:
- static const S32 MAX_DISPLAYED_COUNT;
-
struct Params : public LLInitParam::Block<Params, LLTextBox::Params>
{
/**
@@ -217,7 +215,8 @@ public:
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
- Optional<bool> show_counter;
+ Optional<bool> show_counter,
+ enable_counter;
Params();
};
@@ -323,10 +322,7 @@ public:
};
struct Params : public LLInitParam::Block<Params, LLChiclet::Params>
{
- Optional<std::string> new_messages_icon_name;
-
- Params() : new_messages_icon_name("new_messages_icon_name", "Unread_IM")
- {}
+ Params(){}
};
@@ -437,6 +433,8 @@ protected:
bool mShowSpeaker;
bool mCounterEnabled;
+ /* initial width of chiclet, should not include counter or speaker width */
+ S32 mDefaultWidth;
LLIconCtrl* mNewMessagesIcon;
LLChicletNotificationCounterCtrl* mCounterCtrl;
@@ -482,6 +480,8 @@ public:
Optional<LLChicletSpeakerCtrl::Params> speaker;
+ Optional<LLIconCtrl::Params> new_message_icon;
+
Optional<bool> show_speaker;
Params();
@@ -545,6 +545,8 @@ public:
Optional<LLChicletSpeakerCtrl::Params> speaker;
+ Optional<LLIconCtrl::Params> new_message_icon;
+
Optional<bool> show_speaker;
Optional<LLColor4> avatar_icon_color;
@@ -615,6 +617,8 @@ public:
{
Optional<LLIconCtrl::Params> icon;
+ Optional<LLIconCtrl::Params> new_message_icon;
+
Params();
};
@@ -655,6 +659,8 @@ public:
{
Optional<LLChicletInvOfferIconCtrl::Params> icon;
+ Optional<LLIconCtrl::Params> new_message_icon;
+
Params();
};
@@ -698,6 +704,8 @@ public:
Optional<LLChicletSpeakerCtrl::Params> speaker;
+ Optional<LLIconCtrl::Params> new_message_icon;
+
Optional<bool> show_speaker;
Params();
diff --git a/indra/newview/skins/default/xui/en/widgets/chiclet_im_adhoc.xml b/indra/newview/skins/default/xui/en/widgets/chiclet_im_adhoc.xml
new file mode 100644
index 0000000000..7cb973f4c8
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/chiclet_im_adhoc.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<chiclet_im_adhoc
+ font="SansSerif"
+ height="25"
+ name="im_adhoc_chiclet"
+ show_speaker="false"
+ width="25">
+ <chiclet_im_adhoc.speaker
+ auto_update="true"
+ draw_border="false"
+ height="25"
+ left="25"
+ name="speaker"
+ visible="false"
+ width="20"/>
+ <chiclet_im_adhoc.avatar_icon
+ follows="left|top|bottom"
+ height="22"
+ mouse_opaque="true"
+ name="adhoc_icon"
+ width="22"/>
+ <chiclet_im_adhoc.unread_notifications
+ font="SansSerif"
+ font_halign="center"
+ height="25"
+ left="25"
+ mouse_opaque="false"
+ name="unread"
+ text_color="white"
+ v_pad="5"
+ visible="false"
+ width="20"/>
+ <chiclet_im_adhoc.new_message_icon
+ bottom="12"
+ height="13"
+ image_name="Unread_IM"
+ left="12"
+ name="new_message_icon"
+ visible="false"
+ width="13" />
+</chiclet_im_adhoc> \ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/widgets/chiclet_im_group.xml b/indra/newview/skins/default/xui/en/widgets/chiclet_im_group.xml
new file mode 100644
index 0000000000..a9b567225e
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/chiclet_im_group.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<chiclet_im_group
+ font="SansSerif"
+ height="25"
+ name="im_group_chiclet"
+ show_speaker="false"
+ width="25">
+ <chiclet_im_group.speaker
+ auto_update="true"
+ draw_border="false"
+ height="25"
+ left="25"
+ name="speaker"
+ visible="false"
+ width="20"/>
+ <chiclet_im_group.group_icon
+ default_icon="Generic_Group"
+ follows="left|top|bottom"
+ height="22"
+ mouse_opaque="true"
+ name="group_icon"
+ width="22"/>
+ <chiclet_im_group.unread_notifications
+ height="25"
+ font="SansSerif"
+ font_halign="center"
+ left="25"
+ mouse_opaque="false"
+ name="unread"
+ text_color="white"
+ v_pad="5"
+ visible="false"
+ width="20"/>
+ <chiclet_im_group.new_message_icon
+ bottom="12"
+ height="13"
+ image_name="Unread_IM"
+ left="12"
+ name="new_message_icon"
+ visible="false"
+ width="13" />
+</chiclet_im_group> \ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/widgets/chiclet_im_p2p.xml b/indra/newview/skins/default/xui/en/widgets/chiclet_im_p2p.xml
new file mode 100644
index 0000000000..9283594a4c
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/chiclet_im_p2p.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<chiclet_im_p2p
+ font="SansSerif"
+ height="25"
+ name="im_p2p_chiclet"
+ show_speaker="false"
+ width="25">
+ <chiclet_im_p2p.speaker
+ auto_update="true"
+ draw_border="false"
+ height="25"
+ left="25"
+ name="speaker"
+ visible="false"
+ width="20"/>
+ <chiclet_im_p2p.avatar_icon
+ follows="left|top|bottom"
+ height="22"
+ mouse_opaque="true"
+ name="avatar_icon"
+ width="22"/>
+ <chiclet_im_p2p.unread_notifications
+ height="25"
+ font="SansSerif"
+ font_halign="center"
+ left="25"
+ mouse_opaque="false"
+ name="unread"
+ text_color="white"
+ v_pad="5"
+ visible="false"
+ width="20"/>
+ <chiclet_im_p2p.new_message_icon
+ bottom="12"
+ height="13"
+ image_name="Unread_IM"
+ left="12"
+ name="new_message_icon"
+ visible="false"
+ width="13" />
+</chiclet_im_p2p> \ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/widgets/chiclet_offer.xml b/indra/newview/skins/default/xui/en/widgets/chiclet_offer.xml
new file mode 100644
index 0000000000..5a22563758
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/chiclet_offer.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<chiclet_offer
+ font="SansSerif"
+ height="25"
+ name="offer_chiclet"
+ width="25">
+ <chiclet_offer.icon
+ default_icon="Generic_Object_Small"
+ follows="all"
+ height="22"
+ mouse_opaque="false"
+ name="chiclet_icon"
+ width="22"/>
+ <chiclet_offer.new_message_icon
+ bottom="12"
+ height="13"
+ image_name="Unread_IM"
+ left="12"
+ name="new_message_icon"
+ visible="false"
+ width="13" />
+</chiclet_offer> \ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/widgets/chiclet_script.xml b/indra/newview/skins/default/xui/en/widgets/chiclet_script.xml
index e5af961a56..05a23b95f9 100644
--- a/indra/newview/skins/default/xui/en/widgets/chiclet_script.xml
+++ b/indra/newview/skins/default/xui/en/widgets/chiclet_script.xml
@@ -1,10 +1,22 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<chiclet_script
- name="script_chiclet"
- font="SansSerif">
- <icon
- name="chiclet_icon"
- follows="all"
- mouse_opaque="false"
- image_name="Generic_Object_Small" />
-</expandable_text> \ No newline at end of file
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<chiclet_script
+ font="SansSerif"
+ height="25"
+ name="script_chiclet"
+ width="25">
+ <chiclet_script.icon
+ follows="all"
+ height="22"
+ image_name="Generic_Object_Small"
+ mouse_opaque="false"
+ name="chiclet_icon"
+ width="22"/>
+ <chiclet_script.new_message_icon
+ bottom="12"
+ height="13"
+ image_name="Unread_IM"
+ left="12"
+ name="new_message_icon"
+ visible="false"
+ width="13" />
+</chiclet_script> \ No newline at end of file