lotrointerface.com
Search Downloads

LoTROInterface SVN Calendar

[/] [Release_3.5/] [FrostyPlugins/] [Calendar/] [CalendarEntry.lua] - Rev 35

Compare with Previous | Blame | View Log

import "Turbine";
import "Turbine.Gameplay";
import "Turbine.UI";
import "Turbine.UI.Extensions";
import "Turbine.UI.Lotro";
--import "Turbine.Utils";
import "FrostyPlugins.Calendar.DropDownBox";
import "FrostyPlugins.Calendar.CheckBox";
import "FrostyPlugins.Calendar.Options";

-- Get reference to user configurable options (singleton)
--options = FrostyPlugins.Calendar.OptionsInstance();
--table.dump("options",self.options);

-- --------------------------------------------------------------
-- CalendarEntry is a simple container class that holds and tracks
-- information about an "entry" on the calendar
--
-- Ideally the date/timestamps on each entry would be stored in a 
-- global standard (UTC) to easily share calendar entries 
-- between people in different timezones
-- Unfortunately there doesn't appear to be a way to obtain the
-- current timezone from Turbine.Engine.
--   - GetLocale() does NOT return timezone
-- - so we'll have to save the timezone (TZ) as a calendar setting
--   though converting timestamps is non-trivial.
--
-- For now - save start/end timestamps as 'yyyy-mm-dd hh:mm:ss'
-- in 24 format so they can easily be sorted without converting
-- them to epoch (seconds since 1970-01-01 00:00:00)
-- --------------------------------------------------------------
CalendarEntry = class( Turbine.Object );

local InviteeStatus = {
    INVITED = 1,
    ACCEPTED = 2,
    DECLINED = 3,
}

-- Only include colors that have good contrast to dark background of calendar
local EntryColors = {
    "White",
    "Orange",
    "Blue",
    "SkyBlue",
    "LightBlue",
    "Red",
    "Pink",
    "HotPink",
    "Yellow",
    "Green",
    "LightGreen",
    "Gray",
    "LightGray",
    "Cyan",
};

function CalendarEntry:Constructor()
    Turbine.Object.Constructor( self );

    -- True if entry is editable, false otherwise
    --self.isEditable = true;
    
    self.Start = nil;  -- STRING: yyyy-mm-ddThh:mm:ssz -- the start of the event
    self.End = nil;    -- STRING: yyyy-mm-ddThh:mm:ssz -- the end of the event
    self.isAllDay = false; -- true if the event is all day
    --self.isReminderEnabled = false; -- true if a reminder for this event is enabled
    self.Description = nil; -- one-line title of event
    self.Details = nil;     -- multi-line details about event
    -- Color to display for the event
    -- - must save as colorName, rather than Color object
    self.Color = "White";
    -- A reminder
    --self.Reminder = nil; -- If enabled, how many minutes before eventto display reminder pop-up
    
    -- How to handle this if different character on same account sends update?
    --self.Organizer = nil;  -- who organized the event (if nil, then it is user event)
    -- A map of others this event is shared with to their acceptance status
    --      Invitees{person} = InviteeStatus
    --self.Invitees = {};
end

-- --------------------------------------------------------------
-- CalendarEntryEditor is the editor window that allows the user
-- to change the time of the event or update it's description.
-- the user can also set an alarm / reminder that the time is
-- near.
--
-- ToDo (must wait for API updates)!
-- add a "notify" checkbox to let the user know 15 minutes before the event time
-- add an "alarm" button to alert the user audibly when the event time has been reached
-- AM vs PM?  right now, it is a 24 hour clock
-- 
-- --------------------------------------------------------------

CalendarEntryEditor = class( Turbine.UI.Lotro.Window);

-- --------------------------------------------------------------
-- Constructor
--
-- Description: this is where the window is laid out, the fields
-- and buttons are created, and events are trapped.
-- --------------------------------------------------------------
function CalendarEntryEditor:Constructor()

    --Turbine.Shell.WriteLine("CalendarEntryEditor:Constructor()");
    Turbine.UI.Lotro.Window.Constructor( self );
    
    -- load the last settings saved (we will use the position to locate the editor)
    self:LoadSettings();
    
    -- --------------------------------------------
    -- window layout
    -- --------------------------------------------
    local windowMargin = 20;
    local controlMargin = 5;
    
    -- set window properties
    self:SetSize( 400, 400 ); -- width,height
    self:SetBackColor( Turbine.UI.Color() );
    self:SetPosition( self.settings.positionX, self.settings.positionY );
    self:SetText( "Update Entry..." );
    self:SetOpacity( 1 );
    self:SetAllowDrop( false );
    
    -- create the StatusBar label at bottom of window
    self.statusBarLabel = Turbine.UI.Label();
    self.statusBarLabel:SetParent( self );
    self.statusBarLabel:SetSize( self:GetWidth()-60, 20 ); -- width,height
    self.statusBarLabel:SetPosition( -- left,top
        30,
        self:GetHeight() - self.statusBarLabel:GetHeight() - 5 ); 
    --self.statusBarLabel:SetBackColor(Turbine.UI.Color.DimGray);
    self.statusBarLabel:SetMultiline( false );
    self.statusBarLabel:SetSelectable( false );
    self.statusBarLabel:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    --self.statusBarLabel:SetText( "<Status>" );
    self.statusBarLabel:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleCenter );
    self.statusBarLabel:SetVisible( true );
    
    -- create the date start label
    self.dateStartLabel = Turbine.UI.Label();
    self.dateStartLabel:SetParent( self );
    self.dateStartLabel:SetPosition( windowMargin, 40 ); -- left,top
    self.dateStartLabel:SetSize( 40, 20 ); -- width,height
    --self.dateStartLabel:SetBackColor(Turbine.UI.Color.DimGray);
    self.dateStartLabel:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    self.dateStartLabel:SetMultiline( false );   
    self.dateStartLabel:SetSelectable( false );  
    self.dateStartLabel:SetText( "Start:" );
    self.dateStartLabel:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleRight );
    self.dateStartLabel:SetVisible( true );
    
    -- create the date start textbox
    self.dateStartText = Turbine.UI.TextBox();
    self.dateStartText:SetParent( self );
    self.dateStartText:SetPosition( -- left,top
        self.dateStartLabel:GetLeft() + self.dateStartLabel:GetWidth() + controlMargin,
        self.dateStartLabel:GetTop() ); 
    self.dateStartText:SetSize( -- width,height
        100, 
        self.dateStartLabel:GetHeight() ); 
    self.dateStartText:SetBackColor(Turbine.UI.Color.DimGray);
    self.dateStartText:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    self.dateStartText:SetMultiline( false );  
    self.dateStartText:SetSelectable( true );
    self.dateStartText:SetText( "yyyy-mm-dd" );
    self.dateStartText:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleCenter );
    self.dateStartText:SetVisible( true );

    self.dateStartText.FocusLost = function( sender, args )
        --Turbine.Shell.WriteLine("dateStartText:FocusLost");
        self:isValid(); -- validate if entry can be saved
    end
    
    -- Unfortunately, the validating() method not available in the LOTRO API
    -- Therefore, it is better to constrain user input so it is not possible
    -- to enter invalid input in the first place.  (e.g. use pick lists, etc.)
    --self.dateStartText.Validating = function( sender, args )
    --  Turbine.Shell.WriteLine("dateStartText:Validating");
    --end
    
    -- create the time start textbox
    self.timeStartText = Turbine.UI.TextBox();
    self.timeStartText:SetParent( self );
    self.timeStartText:SetPosition( -- left,top
        self.dateStartText:GetLeft() + self.dateStartText:GetWidth() + controlMargin,
        self.dateStartLabel:GetTop() ); 
    self.timeStartText:SetSize( -- width,height
        60, 
        self.dateStartLabel:GetHeight() ); 
    self.timeStartText:SetBackColor(Turbine.UI.Color.DimGray);
    self.timeStartText:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    self.timeStartText:SetMultiline( false );  
    self.timeStartText:SetSelectable( true );
    self.timeStartText:SetText( "hh:mm" );
    self.timeStartText:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleCenter );
    self.timeStartText:SetVisible( true );

    self.timeStartText.FocusLost = function( sender, args )
        --Turbine.Shell.WriteLine("timeStartText:FocusLost");
        self:isValid(); -- validate if entry can be saved
    end
    
    self.timeStartText.EnabledChanged = function( sender, args )
        local isEnabled = self.timeStartText:IsEnabled();
        --Turbine.Shell.WriteLine("timeStartText:enabledChanged [" .. tostring(isEnabled) .. "]");
        --self.timeStartText:SetVisible(isEnabled);
        if( isEnabled ) then
            self.timeStartText:SetBackColor(Turbine.UI.Color.DimGray);
        else
            self.timeStartText:SetBackColor(Turbine.UI.Color.DarkSlateGray);
        end     
    end
    
    -- create the date end label
    self.dateEndLabel = Turbine.UI.Label();
    self.dateEndLabel:SetParent( self );
    self.dateEndLabel:SetPosition( -- left,top
        self.dateStartLabel:GetLeft(), 
        self.dateStartLabel:GetTop() + self.dateStartLabel:GetHeight() + 5 ); 
    self.dateEndLabel:SetSize( self.dateStartLabel:GetSize() ); -- width,height
    --self.dateEndLabel:SetBackColor(Turbine.UI.Color.DimGray);
    self.dateEndLabel:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    self.dateEndLabel:SetMultiline( false );   
    self.dateEndLabel:SetSelectable( false );  
    self.dateEndLabel:SetText( "End:" );
    self.dateEndLabel:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleRight );
    self.dateEndLabel:SetVisible( true );
    
    -- create the date end textbox
    self.dateEndText = Turbine.UI.TextBox();
    self.dateEndText:SetParent( self );
    self.dateEndText:SetPosition( -- left,top
        self.dateStartText:GetLeft(),
        self.dateEndLabel:GetTop() ); 
    self.dateEndText:SetSize( self.dateStartText:GetSize() ); -- width,height
    self.dateEndText:SetBackColor(Turbine.UI.Color.DimGray);
    self.dateEndText:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    self.dateEndText:SetMultiline( false );   
    self.dateEndText:SetSelectable( true );  
    self.dateEndText:SetText( "yyyy-mm-dd" );
    self.dateEndText:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleCenter );
    self.dateEndText:SetVisible( true );
    
    self.dateEndText.FocusLost = function( sender, args )
        --Turbine.Shell.WriteLine("dateEndText:FocusLost");
        self:isValid(); -- validate if entry can be saved
    end
    
    -- create the time end textbox
    self.timeEndText = Turbine.UI.TextBox();
    self.timeEndText:SetParent( self );
    self.timeEndText:SetPosition( -- left,top
        self.dateEndText:GetLeft() + self.dateEndText:GetWidth() + 5,
        self.dateEndText:GetTop() ); 
    self.timeEndText:SetSize( self.timeStartText:GetSize() ); -- width,height
    self.timeEndText:SetBackColor(Turbine.UI.Color.DimGray);
    self.timeEndText:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    self.timeEndText:SetMultiline( false );  
    self.timeEndText:SetEnabled( true );
    self.timeEndText:SetSelectable( false );
    self.timeEndText:SetText( "hh:mm" );
    self.timeEndText:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleCenter );
    self.timeEndText:SetVisible( true );

    self.timeEndText.FocusLost = function( sender, args )
        --Turbine.Shell.WriteLine("timeEndText:FocusLost");
        self:isValid(); -- validate if entry can be saved
    end
    
    self.timeEndText.EnabledChanged = function( sender, args )
        local isEnabled = self.timeEndText:IsEnabled();
        --Turbine.Shell.WriteLine("timeEndText:enabledChanged [" .. tostring(isEnabled) .. "]");
        --self.timeEndText:SetVisible(isEnabled);
        if( isEnabled ) then
            self.timeEndText:SetBackColor(Turbine.UI.Color.DimGray);
        else
            self.timeEndText:SetBackColor(Turbine.UI.Color.DarkSlateGray);
        end     
    end
    
    -- create the allDay checkbox
    -- - HACK! Seems to be a bug in Lotro.Checkbox not notifying CheckChanged
    --   So use own control to workaround problem
    --self.allDayCheckbox = Turbine.UI.Lotro.CheckBox();
    --self.allDayCheckbox = Turbine.UI.CheckBox();
    self.allDayCheckbox = FrostyPlugins.Calendar.CheckBox();
    self.allDayCheckbox:SetParent( self );
    self.allDayCheckbox:SetPosition( -- left,top
        self.timeStartText:GetLeft() + self.timeStartText:GetWidth() + 5,
        self.timeStartText:GetTop() ); 
    self.allDayCheckbox:SetSize( 80, 20 ); -- width,height
    self.allDayCheckbox:SetBackColor(Turbine.UI.Color.DimGray);
    self.allDayCheckbox:SetOutlineColor( Turbine.UI.Color.Yellow );
    self.allDayCheckbox:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    self.allDayCheckbox:SetVisible( true ); 
    --self.allDayCheckbox:SetEnabled( true );
    self.allDayCheckbox:SetChecked( false );
    --self.allDayCheckbox:SetSelectable( true );
    --self.allDayCheckbox:SetMouseVisible( true );
    --self.allDayCheckbox:SetWantsUpdates( true );
    self.allDayCheckbox:SetText( "All Day" ); -- put text in label
    --self.allDayCheckbox:SetText( "" ); -- put text in label
    
    self.allDayCheckbox.CheckChanged = function( sender, args )
        local isChecked = self.allDayCheckbox:IsChecked();
        --Turbine.Shell.WriteLine("allDayCheckbox:CheckChanged [" .. tostring(isChecked) .. "]");
        
        self.timeStartText:SetEnabled( not isChecked );
        self.timeEndText:SetEnabled( not isChecked );
    end
    
    -- CAUTION: Do NOT override the MouseClick or it will
    -- interfere with the control processing Click events.
    self.allDayCheckbox.MouseEnter = function( sender, args )
        sender:SetFontStyle( Turbine.UI.FontStyle.Outline );
        sender:SetVisible( false );
        sender:SetVisible( true );
    end
    
    self.allDayCheckbox.MouseLeave = function( sender, args )
        sender:SetFontStyle( Turbine.UI.FontStyle.None );
        sender:SetVisible( false );
        sender:SetVisible( true );
    end
    
    -- create the date field
    --self.dateLabel = Turbine.UI.Label();
    --self.dateLabel:SetParent( self );
    --self.dateLabel:SetPosition( -- left,top
    --  self.dateEndLabel:GetLeft(), 
    --  self.dateEndLabel:GetTop() + self.dateEndLabel:GetHeight() + 5 ); 
    --self.dateLabel:SetSize( 180, 20 ); -- width,height
    --self.dateLabel:SetBackColor(Turbine.UI.Color.DimGray);
    --self.dateLabel:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    --self.dateLabel:SetMultiline( false );   
    --self.dateLabel:SetText( "Date:" );
    --self.dateLabel:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleLeft );
    --self.dateLabel:SetVisible( true );
    --self.dateLabel:SetSelectable( false );  
    --self.dateLabel:SetMouseVisible( true );
    --self.dateLabel:SetWantsUpdates( true );
    
    -- create the time field
    --self.timeLabel = Turbine.UI.Label();
    --self.timeLabel:SetParent( self );
    --self.timeLabel:SetPosition( -- left,top
    --  self.dateLabel:GetLeft() + self.dateLabel:GetWidth() + 5, 
    --  self.dateLabel:GetTop() ); 
    --self.timeLabel:SetSize( -- width,height
    --  40, 
    --  self.dateLabel:GetHeight() ); 
    --self.timeLabel:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    --self.timeLabel:SetMultiline( false );   
    --self.timeLabel:SetSelectable( false );  
    --self.timeLabel:SetText( "Time: " );
    --self.timeLabel:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleLeft );
    --self.timeLabel:SetVisible( true );
    --
    --self.hoursUp = Turbine.UI.Button();
    --self.hoursUp:SetParent( self );
    --self.hoursUp:SetPosition( -- left,top
    --  230, 
    --  self.timeLabel:GetTop()-10 ); 
    --self.hoursUp:SetSize( 20, 20 ); -- width,height
    --self.hoursUp:SetBackground( "FrostyPlugins/Calendar/Resources/UpArrow.tga" );
    --self.hoursUp:SetBlendMode( Turbine.UI.BlendMode.Overlay );
    --self.hoursUp:SetVisible( true );
    --
    --self.hoursUp.MouseEnter = function( sender, args )
    --    sender:SetBackground( "FrostyPlugins/Calendar/Resources/UpArrowHighlight.tga" );
    --    self.hoursField:SetForeColor( Turbine.UI.Color( 1, 1, 0 ) );
    --end
    --self.hoursUp.MouseLeave = function( sender, args )
    --    sender:SetBackground( "FrostyPlugins/Calendar/Resources/UpArrow.tga" );
    --    self.hoursField:SetForeColor( Turbine.UI.Color( 1, 1, 1 ) );
    --end
    --
    --self.hoursUp.Click = function( sender, args )
    --    self:AdjustHours( 1 );
    --end
    --
    --self.hoursDown = Turbine.UI.Button();
    --self.hoursDown:SetParent( self );
    --self.hoursDown:SetPosition(  -- left,top
    --  self.hoursUp:GetLeft(), 
    --  self.hoursUp:GetTop() + self.hoursUp:GetHeight() );
    --self.hoursDown:SetSize( -- width,height
    --  self.hoursUp:GetWidth(), 
    --  self.hoursUp:GetHeight() ); 
    --self.hoursDown:SetBackground( "FrostyPlugins/Calendar/Resources/DownArrow.tga" );
    --self.hoursDown:SetBlendMode( Turbine.UI.BlendMode.Overlay );
    --self.hoursDown:SetVisible( true );
    --
    --self.hoursDown.MouseEnter = function( sender, args )
    --    sender:SetBackground( "FrostyPlugins/Calendar/Resources/DownArrowHighlight.tga" );
    --    self.hoursField:SetForeColor( Turbine.UI.Color( 1, 1, 0 ) );
    --end
    --self.hoursDown.MouseLeave = function( sender, args )
    --    sender:SetBackground( "FrostyPlugins/Calendar/Resources/DownArrow.tga" );
    --    self.hoursField:SetForeColor( Turbine.UI.Color( 1, 1, 1 ) );
    --end
    --
    --self.hoursDown.Click = function( sender, args )
    --    self:AdjustHours( -1 );
    --end
    --
    --self.hoursField = Turbine.UI.Label();
    --self.hoursField:SetParent( self );
    --self.hoursField:SetPosition( 255, self.dateLabel:GetTop() ); -- left,top
    --self.hoursField:SetSize( 20, self.dateLabel:GetHeight() ); -- width,height
    --self.hoursField:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    --self.hoursField:SetMultiline( false );  
    --self.hoursField:SetSelectable( false ); 
    --self.hoursField:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleCenter );
    --self.hoursField:SetVisible( true );
    --
    --self.colonField = Turbine.UI.Label();
    --self.colonField:SetParent( self );
    --self.colonField:SetPosition( 275, self.dateLabel:GetTop() ); -- left,top
    --self.colonField:SetSize( 5, self.dateLabel:GetHeight() ); -- width,height
    --self.colonField:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    --self.colonField:SetMultiline( false );  
    --self.colonField:SetSelectable( false ); 
    --self.colonField:SetText( ":" );
    --self.colonField:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleCenter );
    --self.colonField:SetVisible( true );
    --
    --self.minutesField = Turbine.UI.Label();
    --self.minutesField:SetParent( self );
    --self.minutesField:SetPosition( 280, self.dateLabel:GetTop() ); -- left,top
    --self.minutesField:SetSize( 20, self.dateLabel:GetHeight() ); -- width,height
    --self.minutesField:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    --self.minutesField:SetMultiline( false );    
    --self.minutesField:SetSelectable( false );   
    --self.minutesField:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleCenter );
    --self.minutesField:SetVisible( true );
    --
    --self.minutesUp = Turbine.UI.Button();
    --self.minutesUp:SetParent( self );
    --self.minutesUp:SetPosition( -- left,top
    --  300, 
    --  self.hoursUp:GetTop() ); 
    --self.minutesUp:SetSize( -- width,height
    --  self.hoursUp:GetWidth(), 
    --  self.hoursUp:GetHeight() ); 
    --self.minutesUp:SetBackground( "FrostyPlugins/Calendar/Resources/UpArrow.tga" );
    --self.minutesUp:SetBlendMode( Turbine.UI.BlendMode.Overlay );
    --self.minutesUp:SetVisible( true );
    --
    --self.minutesUp.MouseEnter = function( sender, args )
    --    sender:SetBackground( "FrostyPlugins/Calendar/Resources/UpArrowHighlight.tga" );
    --    self.minutesField:SetForeColor( Turbine.UI.Color( 1, 1, 0 ) );
    --end
    --self.minutesUp.MouseLeave = function( sender, args )
    --    sender:SetBackground( "FrostyPlugins/Calendar/Resources/UpArrow.tga" );
    --    self.minutesField:SetForeColor( Turbine.UI.Color( 1, 1, 1 ) );
    --end
    --
    --self.minutesUp.Click = function( sender, args )
    --    self:AdjustMinutes( 1 );
    --end
    --
    --self.minutesDown = Turbine.UI.Button();
    --self.minutesDown:SetParent( self );
    --self.minutesDown:SetPosition( -- left,top
    --  300, 
    --  self.hoursUp:GetTop() + self.hoursUp:GetHeight() );
    --self.minutesDown:SetSize( -- width,height
    --  self.hoursUp:GetWidth(), 
    --  self.hoursUp:GetHeight() );     
    --self.minutesDown:SetBackground( "FrostyPlugins/Calendar/Resources/DownArrow.tga" );
    --self.minutesDown:SetBlendMode( Turbine.UI.BlendMode.Overlay );
    --self.minutesDown:SetVisible( true );
    --
    --self.minutesDown.MouseEnter = function( sender, args )
    --  sender:SetBackground( "FrostyPlugins/Calendar/Resources/DownArrowHighlight.tga" );
    --  self.minutesField:SetForeColor( Turbine.UI.Color( 1, 1, 0 ) );
    --end
    --self.minutesDown.MouseLeave = function( sender, args )
    --  sender:SetBackground( "FrostyPlugins/Calendar/Resources/DownArrow.tga" );
    --  self.minutesField:SetForeColor( Turbine.UI.Color( 1, 1, 1 ) );
    --end
    --
    --self.minutesDown.Click = function( sender, args )
    --    self:AdjustMinutes( -1 );
    --end
  
    -- fixme: frosty
    --        alarm button?
    --        notify button?
        
    self.buttonEntryColor  = FrostyPlugins.Calendar.DropDownBox{itemList=EntryColors};
    self.buttonEntryColor:SetParent( self );
    self.buttonEntryColor:SetPosition( -- left,top
        self.allDayCheckbox:GetLeft(),
    self.dateEndLabel:GetTop() ); 
    self.buttonEntryColor:SetSize( -- width,height
        self.allDayCheckbox:GetWidth(),
        self.dateEndLabel:GetHeight() ); 
    self.buttonEntryColor:SetText( "Color" );
    self.buttonEntryColor:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleCenter );
    --self.buttonEntryColor:SetBackColor(Turbine.UI.Color.Gray);
    self.buttonEntryColor.SelectionChanged = function( sender, args )
        local idx = self.buttonEntryColor:GetSelectedIndex();
        local colorName = self.buttonEntryColor:GetSelectedValue();
        --Turbine.Shell.WriteLine( string.format(
        --  "buttonEntryColor.SelectionChanged: [%d] = [%s]",
        --  idx, colorName) );
        --self.buttonEntryColor:SetBackColor(Turbine.UI.Color[color]);
        self.buttonEntryColor:SetForeColor( Turbine.UI.Color[colorName] );
        self.Color = colorName;
    end
    
    -- create the Description label and field
    self.descriptionLabel = Turbine.UI.Label();
    self.descriptionLabel:SetParent( self );
    self.descriptionLabel:SetPosition( -- left,top
        self.dateEndLabel:GetLeft(),
        self.dateEndLabel:GetTop() + self.dateEndLabel:GetHeight() + windowMargin ); 
    self.descriptionLabel:SetSize( -- width,height
        self:GetWidth() - windowMargin*2,
        self.dateEndLabel:GetHeight() ); 
    self.descriptionLabel:SetMultiline( false );    
    self.descriptionLabel:SetSelectable( false );   
    self.descriptionLabel:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    self.descriptionLabel:SetText( "Description:" );
    self.descriptionLabel:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleLeft );
    self.descriptionLabel:SetVisible( true );
    
    self.descriptionField = Turbine.UI.Lotro.TextBox();
    self.descriptionField:SetParent( self );
    self.descriptionField:SetPosition( -- left,top
        --self.dateLabel:GetLeft(),
        self.dateEndLabel:GetLeft(),
        self.descriptionLabel:GetTop() + self.descriptionLabel:GetHeight() ); 
    self.descriptionField:SetSize( -- width,height
        self:GetWidth() - windowMargin*2,
        self.descriptionLabel:GetHeight() ); 
    self.descriptionField:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    self.descriptionField:SetText( "Description stuff:" );
    self.descriptionField:SetMultiline( false ); 
    self.descriptionField:SetSelectable( true );
    self.descriptionField:SetTextAlignment( Turbine.UI.ContentAlignment.TopLeft );
    self.descriptionField:SetVisible( true );
    
    self.descriptionField.FocusLost = function( sender, args )
        --Turbine.Shell.WriteLine("descriptionField:FocusLost");
        self:isValid(); -- validate if entry can be saved
    end
    
    -- create the Details label and field
    self.detailsLabel = Turbine.UI.Label();
    self.detailsLabel:SetParent( self );
    self.detailsLabel:SetPosition( -- left,top
        self.descriptionLabel:GetLeft(),
        self.descriptionField:GetTop() + self.descriptionField:GetHeight() + windowMargin ); 
    self.detailsLabel:SetSize( self.descriptionLabel:GetSize() ); -- width,height
    self.detailsLabel:SetMultiline( false );    
    self.detailsLabel:SetSelectable( false );   
    self.detailsLabel:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    self.detailsLabel:SetText( "Details:" );
    self.detailsLabel:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleLeft );
    self.detailsLabel:SetVisible( true );

    self.detailsField = Turbine.UI.Lotro.TextBox();
    self.detailsField:SetParent( self );
    self.detailsField:SetPosition( -- left,top
        self.detailsLabel:GetLeft(),
        self.detailsLabel:GetTop() + self.detailsLabel:GetHeight() ); 
    self.detailsField:SetSize( -- width,height
        self.descriptionField:GetWidth(),
        120 ); 
    self.detailsField:SetFont( Turbine.UI.Lotro.Font.Verdana16 );
    self.detailsField:SetMultiline( true ); 
    self.detailsField:SetSelectable( true );
    self.detailsField:SetTextAlignment( Turbine.UI.ContentAlignment.TopLeft );
    self.detailsField:SetVisible( true );

    self.detailsField.FocusLost = function( sender, args )
        --Turbine.Shell.WriteLine("detailsField:FocusLost");
        self:isValid(); -- validate if entry can be saved
    end
    
    -- create the save button
    self.buttonSave = Turbine.UI.Lotro.Button();
    self.buttonSave:SetParent( self );
    self.buttonSave:SetPosition( -- left,top
        40, 
        self.detailsField:GetTop() + self.detailsField:GetHeight() + windowMargin ); 
    self.buttonSave:SetSize( 80, 25 ); -- width,height
    self.buttonSave:SetText( "Save" );
    self.buttonSave:SetVisible( true );
    self.buttonSave:SetEnabled( false ); -- only enable if description provided
    
    self.buttonSave.Click = function( sender, args )
        self:Save();
    end

    -- create the Delete button
    self.buttonDelete = Turbine.UI.Lotro.Button();
    self.buttonDelete:SetParent( self );
    self.buttonDelete:SetPosition( -- left,top
        195, 
        self.buttonSave:GetTop() ); 
    --self.buttonClear:SetSize( 80, 25 ); -- width,height
    self.buttonDelete:SetSize( self.buttonSave:GetSize() ); -- width,height
    self.buttonDelete:SetText( "Delete" );
    self.buttonDelete:SetVisible( true );

    self.buttonDelete.Click = function( sender, args )
        self:Delete();
    end
    
    -- create the cancel button
    self.buttonCancel = Turbine.UI.Lotro.Button();
    self.buttonCancel:SetParent( self );
    self.buttonCancel:SetPosition( -- left,top
        280, 
        self.buttonSave:GetTop() ); 
    --self.buttonCancel:SetSize( 80, 25 );
    self.buttonCancel:SetSize( self.buttonSave:GetSize() ); -- width,height
    self.buttonCancel:SetText( "Cancel" );
    self.buttonCancel:SetVisible( true );

    self.buttonCancel.Click = function( sender, args )
        --Turbine.Shell.WriteLine("buttonCancel.Click");
        self:Cancel();
    end
  
    -- make sure we listen for key presses
    self:SetWantsKeyEvents( true );

    -- --------------------------------------------
    -- event handling
    -- --------------------------------------------

    --self.descriptionField.TextChanged = function( sender, args )
    --  -- Check if description is blank
    --  local description = self.descriptionField:GetText();
    --  local hasDescription = ( string.len(description) > 0 );
    --  -- Enable 'save' button if description provided
    --  self.buttonSave:SetEnabled( hasDescription );
    --end
    
    --
    -- if the escape key is pressed, assume it is a "cancel"
    --
    self.KeyDown = function( sender, args )
        if( Turbine.UI.Lotro.Action.Escape == args.Action ) then
            sender:Cancel();
        end
    end

    --
    -- if the position changes, save the new window location
    --
    self.PositionChanged = function( sender, args )
        local x, y = self:GetPosition();
        self.settings.positionX = x;
        self.settings.positionY = y;
        self:SaveSettings();
    end
end

-- --------------------------------------------------------------
-- AdjustHours
--
-- Description: the user has pressed one of the hours buttons
-- (up or down).  This function is used to bounds check the number
-- of hours and update the displayed hours field.
--
-- Params:
-- delta - integer - the amount of time to change the hours by.
--                   this will be 1 or -1 hours
-- --------------------------------------------------------------
function CalendarEntryEditor:AdjustHours( delta )
    self.hours = self.hours + delta;
    if( self.hours < 0 ) then
      self.hours = 23;
    end
    if( self.hours > 23 ) then
      self.hours = 0;
    end
    
    local newHoursLabel = tostring( self.hours );
    if( self.hours < 10 ) then
      newHoursLabel = "0" .. self.hours;
    end
    self.hoursField:SetText( newHoursLabel );
end

-- --------------------------------------------------------------
-- AdjustMinutes
--
-- Description: the user has pressed one of the minutes buttons
-- (up or down).  This function is used to bounds check the number
-- of minutes and update the displayed minutes field.
--
-- Params:
-- delta - integer - the amount of time to change the minues by.
--                   this will be 1 or -1 minutes
-- --------------------------------------------------------------
function CalendarEntryEditor:AdjustMinutes( delta )
    self.minutes = self.minutes + delta;
    if( self.minutes < 0 ) then
      self.minutes = 59;
    end
    if( self.minutes > 59 ) then
      self.minutes = 0;
    end
    
    local newMinutesLabel = tostring( self.minutes );
    if( self.minutes < 10 ) then
      newMinutesLabel = "0" .. self.minutes;
    end
    self.minutesField:SetText( newMinutesLabel );
end

--------------------------------------------------------------------------
--- isValid
--
-- Description: Check if the user supplied data is valid
-- @return true if valid, false otherwise
-- --------------------------------------------------------------
function CalendarEntryEditor:isValid()
    local strStartDate = string.format("%sT%s:00",
        self.dateStartText:GetText(),
        self.timeStartText:GetText() );
    --Turbine.Shell.WriteLine(string.format("isValid strStartDate = [%s]",strStartDate));
    local status,err = pcall( DateTime.parse, DateTime, strStartDate);
    if( not status ) then
        local msg = string.format("Start Date is invalid: %s",err);
        self.statusBarLabel:SetText(msg);
        self.statusBarLabel:SetForeColor(Turbine.UI.Color.Red);
        --self.statusBarLabel:SetBackColor(Turbine.UI.Color.DimGray);       
        self.dateStartText:SetBackColor(Turbine.UI.Color.Red);
        self.buttonSave:SetEnabled( false );
        return false;
    end
    local now = DateTime:now();
    local minYear = now.Year - (Options.yearLimit-1);
    local maxYear = now.Year + (Options.yearLimit-1);
    --Turbine.Shell.WriteLine(string.format(
    --    "isValid yearLimit[%d] minYear[%d] maxYear[%d]",
    --    Options.yearLimit,
    --    minYear,
    --    maxYear));
    local startDate = DateTime:parse(strStartDate);
    if( startDate.Year > maxYear ) then
        local msg = string.format("Start year must be less than [%d]",maxYear);
        self.statusBarLabel:SetText(msg);
        self.statusBarLabel:SetForeColor(Turbine.UI.Color.Red);
        self.dateEndText:SetBackColor(Turbine.UI.Color.Red);
        self.buttonSave:SetEnabled( false );
        return false;
    end
    if( startDate.Year < minYear ) then
        local msg = string.format("Start year must be more than [%d]",minYear);
        self.statusBarLabel:SetText(msg);
        self.statusBarLabel:SetForeColor(Turbine.UI.Color.Red);
        self.dateEndText:SetBackColor(Turbine.UI.Color.Red);
        self.buttonSave:SetEnabled( false );
        return false;
    end
    --Turbine.Shell.WriteLine("dateStartText is ok");
    self.dateStartText:SetBackColor(Turbine.UI.Color.DimGray);
    
    local strEndDate = string.format("%sT%s:00",
        self.dateEndText:GetText(),
        self.timeEndText:GetText() );
    --Turbine.Shell.WriteLine(string.format("isValid strEndDate = [%s]",strEndDate));
    local status,err = pcall( DateTime.parse, DateTime, strEndDate);
    if( not status ) then
        local msg = string.format("End Date is invalid: %s",err);
        self.statusBarLabel:SetText(msg);
        self.statusBarLabel:SetForeColor(Turbine.UI.Color.Red);
        self.dateEndText:SetBackColor(Turbine.UI.Color.Red);
        self.buttonSave:SetEnabled( false );
        return false;
    end
    -- Verify end date is AFTER start date
    local endDate = DateTime:parse(strEndDate);
    if( startDate > endDate ) then
        local msg = "endDate must be after startDate";
        self.statusBarLabel:SetText(msg);
        self.statusBarLabel:SetForeColor(Turbine.UI.Color.Red);
        self.dateEndText:SetBackColor(Turbine.UI.Color.Red);
        self.buttonSave:SetEnabled( false );
        return false;
    end
    if( endDate.Year > maxYear ) then
        local msg = string.format("End year must be less than [%d]",maxYear);
        self.statusBarLabel:SetText(msg);
        self.statusBarLabel:SetForeColor(Turbine.UI.Color.Red);
        self.dateEndText:SetBackColor(Turbine.UI.Color.Red);
        self.buttonSave:SetEnabled( false );
        return false;
    end
    if( endDate.Year < minYear ) then
        local msg = string.format("End year must be more than [%d]",minYear);
        self.statusBarLabel:SetText(msg);
        self.statusBarLabel:SetForeColor(Turbine.UI.Color.Red);
        self.dateEndText:SetBackColor(Turbine.UI.Color.Red);
        self.buttonSave:SetEnabled( false );
        return false;
    end
    local duration = endDate:DaysSince(startDate);
    if( duration >= Options.maxEventDurationAllDays ) then
        local msg = string.format(
            "All Day events cannot exceed %d days",
            Options.maxEventDurationAllDays);
        self.statusBarLabel:SetText(msg);
        self.statusBarLabel:SetForeColor(Turbine.UI.Color.Red);
        self.dateEndText:SetBackColor(Turbine.UI.Color.Red);
        self.buttonSave:SetEnabled( false );
        return false;
    end
    if( not self.allDayCheckbox:IsChecked() and 
        (duration >= Options.maxEventDurationPartialDays) ) then
        local msg = string.format(
            "Partial day events cannot exceed %d days",
            Options.maxEventDurationPartialDays);
        self.statusBarLabel:SetText(msg);
        self.statusBarLabel:SetForeColor(Turbine.UI.Color.Red);
        self.dateEndText:SetBackColor(Turbine.UI.Color.Red);
        self.buttonSave:SetEnabled( false );
        return false;
    end
    -- Verify duration of event is not too long
    self.dateEndText:SetBackColor(Turbine.UI.Color.DimGray);
    
    -- Verify description provided
    if( string.len(self.descriptionField:GetText()) > 0 ) then
        self.descriptionField:SetBackColor(Turbine.UI.Color.Black);
    else
        local msg = "Missing description!";
        self.statusBarLabel:SetText(msg);
        self.statusBarLabel:SetForeColor(Turbine.UI.Color.Red);
        self.descriptionField:SetBackColor(Turbine.UI.Color.Red);
        self.buttonSave:SetEnabled( false );
        return false;
    end

    -- If it is a read-only entry (e.g. Global Event)
    -- then don't allow it to be saved/changed
    local isReadOnly = (nil ~= self.calendarEntry.ReadOnly) and 
        self.calendarEntry.ReadOnly;
    self.buttonDelete:SetEnabled(not isReadOnly);
    self.buttonSave:SetEnabled(not isReadOnly);
    if( isReadOnly ) then
        local msg = "Entry is read only";
        self.statusBarLabel:SetText(msg);
        self.statusBarLabel:SetForeColor(Turbine.UI.Color.Yellow);
        return false;
    end
    
    -- If you made it this far, it is valid
    -- so enable 'save' button
    self.buttonSave:SetEnabled( true );
    
    if( endDate < now ) then
        local msg = "End date is in the past";
        self.statusBarLabel:SetText(msg);
        self.statusBarLabel:SetForeColor(Turbine.UI.Color.Yellow);
        --self.dateEndText:SetBackColor(Turbine.UI.Color.Red);
        --self.buttonSave:SetEnabled( false );
        return true; -- just a warning
    end
    if( startDate < now ) then
        local msg = "Start date is in the past";
        self.statusBarLabel:SetText(msg);
        self.statusBarLabel:SetForeColor(Turbine.UI.Color.Yellow);
        --self.dateEndText:SetBackColor(Turbine.UI.Color.Red);
        --self.buttonSave:SetEnabled( false );
        return true; -- just a warning
    end
    
    self.statusBarLabel:SetForeColor(Turbine.UI.Color.DimGray);
    self.statusBarLabel:SetText("Entry is valid");
    
    return true;
end

--------------------------------------------------------------------------
--- Save
--
-- Description: the user has pressed the "Save" button.  Notify
-- the calendar that the enclosed CalendarEntry should be saved.
-- --------------------------------------------------------------
function CalendarEntryEditor:Save()
    local calendarEntry = self.calendarEntry;
    Turbine.Shell.WriteLine("CalendarEntryEditor:Save " .. tostring(calendarEntry));

    -- Do *NOT* update the dateEntry field
    -- - the calenderWindow will use to to find the old entry in case
    --   the user changed the start date
    -- - the calender window update this field prior to saving it

    -- update the entry with data from the window controls
    calendarEntry.Start = string.format("%sT%s:00",
        self.dateStartText:GetText(),
        self.timeStartText:GetText());
    calendarEntry.End   = string.format("%sT%s:00",
        self.dateEndText:GetText(),
        self.timeEndText:GetText());
    calendarEntry.isAllDay = self.allDayCheckbox:IsChecked();
    --self.isReminderEnabled = self.reminderCheckbox:IsChecked();
    calendarEntry.Description = self.descriptionField:GetText();
    calendarEntry.Details = self.detailsField:GetText();
    calendarEntry.Color = self.Color;
    
    --table.dump("calendarEntry",calendarEntry);
    
    -- save the settings - notify the creator that the data is ready  
    if( self.notifyCalendar ) then
        self.notifyCalendar:NotifySaveEntry( calendarEntry );
    end
    
    self:SetVisible( false ); -- hide editor window
end

-- --------------------------------------------------------------
-- Cancel
--
-- Description: the user has pressed the "Cancel" button.  There
-- is nothing to do but hide the window.
-- --------------------------------------------------------------
function CalendarEntryEditor:Cancel()
    --Turbine.Shell.WriteLine("CalendarEntryEditor:Cancel");
    -- turn ourselves invisible, nothing else to do
    self:SetVisible( false );
end

-- --------------------------------------------------------------
--- Clear
--
-- Description: the user has pressed the "Delete" button.  
-- Notify the calendar that the enclosed CalendarEntry should be cleared.
-- --------------------------------------------------------------
function CalendarEntryEditor:Delete()
    --Turbine.Shell.WriteLine("CalendarEntryEditor:Delete");
    
    -- TODO - prompt "Are you sure?"
    
    -- notify the creator that the data should be deleted
    if( self.notifyCalendar ) then
      self.notifyCalendar:NotifyDeleteEntry( self );
    end
    
    self:SetVisible( false );
end

-- --------------------------------------------------------------
--- InitializeEntry
--
-- Description: the entry is used to populate the fields on the editor.
-- If the user hits Save or Clear the input calendar is used to notify
-- of data changes.
-- 
-- @param entry - a CalendarEntry passed in from the calendar
-- @param calendar - the CalendarWindow that owns this object
-- --------------------------------------------------------------
function CalendarEntryEditor:InitializeEntry( entry, calendar )
    --Turbine.Shell.WriteLine( "CalendarEntryEditor:InitializeEntry(" .. tostring(entry) .. ")" );
    
    self.notifyCalendar = calendar; -- who to notify
    self.calendarEntry = entry;     -- the entry to add/update
    
    --table.dump("calendarEntry",entry);
    
    self.allDayCheckbox:SetChecked( entry.isAllDay );
    -- call this manually since it doesn't seem to happen on its own
    self.allDayCheckbox:CheckChanged();
    
    local dateEntry = entry.DateEntry;
    
    --Turbine.Shell.WriteLine( " start=" .. entry.Start );
    self:InitializeDateFields( 
        entry.Start, 
        self.dateStartText, 
        self.timeStartText );
    
    --Turbine.Shell.WriteLine( " end=" .. entry.End );
    self:InitializeDateFields( 
        entry.End, 
        self.dateEndText, 
        self.timeEndText );
    
    if( "string" == type(entry.Color) ) then
        self.Color = entry.Color;
    else
        self.Color = "White";
    end
    self.buttonEntryColor:SetSelectedValue(self.Color);
    
    --if( not entry.Start ) then
    --  entry.TimeEntry = "12:00";
    --  Turbine.Shell.WriteLine( "entry.TimeEntry = [" .. entry.TimeEntry .. "]" );
    --end
    --if( not entry.DateStart ) then
    --    entry.DateStart = CalTools:Date(today);
    --  entry.DateStart.Minute = 0;
    --  Turbine.Shell.WriteLine( "entry.DateStart = [" .. entry.DateStart:tostring() .. "]" );
    --end
    --if( not entry.DateEnd ) then
    --    entry.DateEnd = CalTools:Date(today);
    --  entry.DateStart.Hour = 24;
    --  entry.DateStart.Minute = 0;
    --  entry.isAllDay = true;
    --    entry.Description = "Enter text here...";
    --  Turbine.Shell.WriteLine( "entry.DateEnd = [" .. entry.DateEnd:tostring() .. "]" );
    --end
    

    -- the user has clicked on a date entry - populate our fields with the data
    -- that they have specified and update the screen
    -- note: it is assumed that the entry.DateEntry is 5 characters, and in
    --       the format "12:59" or "03:45"
    --if( string.len( entry.TimeEntry) ~= 5 ) then
    --  self.hours = "12";
    --  self.minutes = "59";
    --else
    --  self.hours = string.sub( entry.TimeEntry, 1, 2 );
    --  self.minutes = string.sub( entry.TimeEntry, 4, 5 );
    --end
    
    -- I cheat here by adjusting the hours and minutes by "0", which will cause
    -- them to redisplay using their new values
    --self:AdjustHours( 0 );
    --self:AdjustMinutes( 0 );
    
    self.descriptionField:SetText( entry.Description );
    --self.descriptionField:TextChanged(sender, args); -- force update
    
    self.detailsField:SetText( entry.Details );
    
    -- select all the text and make the field have focus
    -- fixme: frosty
    --        API does not yet support focus setting
    --        * without focus, placing the cursor in the field
    --          will remove the selection - boo!
    -- self.descriptionField:SelectAll();
    
    -- now show ourselves
    self:SetVisible( true );
    self:Activate( true ); -- bring window to front

    self:isValid(); -- validate if entry can be saved
end

-- --------------------------------------------------------------
-- InitializeDateFields
--
-- Description: the entry is used to populate the fields on the editor.
-- If the user hits Save or Clear the input calendar is used to notify
-- of data changes.
-- 
-- @param szDate - the date in UTC zulu time
-- @param dateField - the date TextBox control to initialize
-- @param timeField - the time TextBox control to initialize
-- --------------------------------------------------------------
function CalendarEntryEditor:InitializeDateFields( szDate, dateField, timeField )
    --Turbine.Shell.WriteLine( "CalendarEntryEditor:InitializeDateFields" .. 
    --  " str=[" .. szDate .. "]");
    
    --local tmp = DateTime:parse("1988-12-20 23:45Z");
    --Turbine.Shell.WriteLine( "CalendarEntryEditor:InitializeDateFields" .. 
    --  " tmp=[" .. tmp:tostring() .. "]");
    
    local d = DateTime:parse(szDate);
    if( not d ) then
        Turbine.Shell.WriteLine( "  Detected invalid date[" .. szDate .. "]");
        d = DateTime:now();
    end
    
    dateField:SetText( d:ymd() );
    timeField:SetText( d:time() );
end

-- --------------------------------------------------------------
-- LoadSettings
--
-- Description: loads our internal settings from disk.  For this class,
-- this includes the position of the editor window.  if the position does
-- not exist, we attempt to place it in the center of the window.
-- --------------------------------------------------------------
function CalendarEntryEditor:LoadSettings()
    -- load the settings.  If a value is not available, set a default value
    self.settings = Turbine.PluginData.Load( 
--      Turbine.DataScope.Character, 
        Turbine.DataScope.Account, 
        "CalendarEntrySettings" );
    
    if ( type( self.settings ) ~= "table" ) then
        self.settings = { };
    end

    -- load prior window position
    if ( not self.settings.positionX ) then
        self.settings.positionX = (Turbine.UI.Display.GetWidth() / 2) - (self:GetWidth() / 2 ); 
    end
    if ( not self.settings.positionY ) then
        self.settings.positionY = (Turbine.UI.Display.GetHeight() / 2) - (self:GetHeight() / 2 );
    end
end

-- --------------------------------------------------------------
-- SaveSettings
--
-- Description: save our internal settings to disk.  For this class,
-- this includes the position of the editor window
-- --------------------------------------------------------------
function CalendarEntryEditor:SaveSettings()
    -- save the settings
    Turbine.PluginData.Save( 
--      Turbine.DataScope.Character, 
        Turbine.DataScope.Account, 
        "CalendarEntrySettings", 
        self.settings );
end

Compare with Previous | Blame


All times are GMT -5. The time now is 07:40 PM.


Our Network
EQInterface | EQ2Interface | Minion | WoWInterface | ESOUI | LoTROInterface | MMOUI | Swtorui