# aardio 范例: 中国节假日一览图



```aardio
import win.ui;
import time.holidays.cn;
import fonts.fontAwesome;
/*DSG{{*/
var winform = win.form(text="中国节假日一览图";right=1279;bottom=719;bgcolor=0xF5F5F5)
winform.add(
comboYear={cls="combobox";left=1147;top=15;right=1257;bottom=41;dr=1;dt=1;edge=1;items={};mode="dropdown";z=4};
headerBg={cls="bkplus";left=0;top=0;right=1280;bottom=55;bgcolor=0xB5513F;dl=1;dr=1;dt=1;z=1};
holidayView={cls="plus";left=0;top=55;right=1280;bottom=720;bgcolor=0xF5F5F5;clipBk=false;db=1;dl=1;dr=1;dt=1;notify=1;z=5};
labelYear={cls="bkplus";text="年份";left=1100;top=12;right=1140;bottom=40;color=0xFFFFFF;dr=1;dt=1;font=LOGFONT(h=-14);z=3};
lbToday={cls="static";left=362;top=13;right=1089;bottom=41;bgcolor=0xB5513F;center=1;color=0xFFFFFF;dl=1;dr=1;dt=1;font=LOGFONT(h=-15);z=11};
legendFestival={cls="plus";text="节日当天";left=102;top=15;right=181;bottom=41;align="left";bgcolor=0xFFFFFF;clipBk=false;color=0x333333;dl=1;dt=1;iconColor=0x33C3FF;iconStyle={align="left";font=LOGFONT(name='FontAwesome')};iconText='\uF111';textPadding={left=17};z=10};
legendHoliday={cls="plus";text="放假";left=42;top=15;right=96;bottom=41;align="left";bgcolor=0xFFFFFF;clipBk=false;color=0x333333;dl=1;dt=1;iconColor=0x33A326;iconStyle={align="left";font=LOGFONT(name='FontAwesome')};iconText='\uF111';textPadding={left=17};z=9};
legendNormalWorkDay0={cls="plus";text="照常班休";left=186;top=15;right=267;bottom=41;align="left";bgcolor=0xFFFFFF;clipBk=false;color=0x333333;dl=1;dt=1;iconColor=0x339378;iconStyle={align="left";font=LOGFONT(name='FontAwesome')};iconText='\uF111';textPadding={left=17};z=8};
legendWorkDay={cls="plus";text="补班";left=273;top=15;right=329;bottom=41;align="left";bgcolor=0xFFFFFF;clipBk=false;color=0x333333;dl=1;dt=1;iconColor=0x3353EF;iconStyle={align="left";font=LOGFONT(name='FontAwesome')};iconText='\uF111';textPadding={left=17};z=7};
plus={cls="plus";left=21;top=9;right=343;bottom=45;border={color=0xFFFFFF;radius=4;width=1};dl=1;dt=1;forecolor=0xFFFFFF;z=2};
tooltip={cls="plus";left=100;top=200;right=280;bottom=290;border={color=0xE0E0E0;radius=8;width=1};dl=1;dt=1;visible=false;z=6}
)
/*}}*/

var currentYear = time().year;
for(y = currentYear - 1; currentYear + 1) {
    winform.comboYear.add(y + " 年");
}
winform.comboYear.selIndex = 2;

var holidays = {};
var groupedHolidays = {};
var scrollY = 0;
var maxScrollY = 0;

var colors = {
    holiday = 0xFF26A69A;
    workday = 0xFFEF5350;
    normalWork = 0xFF78909C;
    festival = 0xFFFFCA28;
    
    textPrimary = 0xFFFFFFFF;
    textDark = 0xFF424242;
    textLight = 0xFF757575;
    
    cardBg = 0xFFFFFFFF;
    shadow = 0x1A000000;
    line   = 0xFFEEEEEE;
};

var festivalIcons = {
    ["元旦"] = '\uF0E8';
    ["春节"] = '\uF000';
    ["清明节"] = '\uF06C';
    ["劳动节"] = '\uF0AD';
    ["端午节"] = '\uF06B';
    ["中秋节"] = '\uF186';
    ["国庆节"] = '\uF024';
};

var todayStatus;
var loadHolidays = function(year) {
    holidays = time.holidays.cn.get(year);
    
    groupedHolidays = {};
    var currentGroup = null;
    
    var now = time(,"%Y-%m-%d");
    var nowStr = tostring(now);
    todayStatus = null;
    
    for(i, holiday in holidays) {
        
        if(!festivalIcons[holiday.name] && string.indexOf(holiday.name,"国庆")&&string.indexOf(holiday.name,"中秋")){
        	holiday.name = "国庆节"  
        }
        
        if(!currentGroup || currentGroup.name != holiday.name) {
            currentGroup = {
                name = holiday.name;
                days = {};
                hasHoliday = false;
                holidayCount = 0;
                workCount = 0;
            };
            table.push(groupedHolidays, currentGroup);
        }
        table.push(currentGroup.days, holiday);
        
        if(holiday.isOffDay) {
            currentGroup.holidayCount++;
            currentGroup.hasHoliday = true; 
        } else {
            currentGroup.workCount++;
        }
        
        if(!todayStatus){
            var tmHoliday = time.date(holiday.date);
            if(holiday.date == nowStr ){
                if(holiday.isOffDay){
                	todayStatus = "今天正在放假("+ holiday.name+")";
                } 
                else{
                	todayStatus = ""
                }
                
            }
            elseif(tmHoliday > now){
                
                // tmHoliday 的时间部分是 0 点
                var days = ..math.ceil(tmHoliday.diffHours(now) / 24);
                // var days = tmHoliday.diffDays(now);
                    
                if( days < 30 ){
                    todayStatus = "离" + holiday.name + "还有 " + days + " 天";
                }
            }
        }
    }
    
    scrollY = 0;
};

winform.holidayView.onDrawForeground = function(graphics,rc,foregroundRect,foregroundColor,color,font){

    var dpiX, dpiY = winform.dpiScale(1, 1); 
    
    var strFormat = gdip.stringFormat();
    strFormat.align = 1;
    strFormat.lineAlign = 1;
    
    var strformatLeft = gdip.stringFormat();
    strformatLeft.align = 0;
    strformatLeft.lineAlign = 1;
    
    if(#groupedHolidays == 0) { 
        var fontEmpty = gdip.font("Tahoma",14, 0, 3/*_UnitPoint*/);
        var emptyBrush = gdip.solidBrush(colors.textLight);
        graphics.drawString("暂无该年度数据，请选择其他年份", fontEmpty, ::RECTF(0, 0, rc.right, rc.bottom-50*dpiY), strFormat, emptyBrush);
        emptyBrush.delete(); 
        fontEmpty.delete();
        strFormat.delete();
        strformatLeft.delete();
        return true;
    }
    
    var leftMargin = 145 * dpiX;
    var topMargin = 15 * dpiY;
    var rowHeight = 79 * dpiY;
    var dayWidth = 75 * dpiX;
    var dayHeight = 65 * dpiY;
    var gap = 5 * dpiX;
    var rowGap = 15 * dpiY;
    
    var fontTitle = gdip.font("Tahoma",12, 1, 3);
    var fontDay = gdip.font("Arial", 10, 1, 3);
    var fontIcon = gdip.font("FontAwesome", 18, 0, 3);
    
    var y = topMargin - scrollY;
    var contentHeight = #groupedHolidays * rowHeight + topMargin * 2;
    maxScrollY = math.max(0, contentHeight - rc.bottom);
    
    for(i, group in groupedHolidays) {
        if(y + rowHeight > 0 && y < rc.bottom) {
            
            var cardRect = ::RECTF(10*dpiX, y, leftMargin - 25*dpiX, rowHeight - rowGap);
            var cardPath = gdip.path();
            cardPath.addRoundRect(cardRect, 8*dpiX);
            
            var shadowPath = gdip.path();
            shadowPath.addRoundRect(cardRect.x+2, cardRect.y+2, cardRect.width, cardRect.height, 8*dpiX);
            var shadowBrush = gdip.solidBrush(colors.shadow);
            graphics.fillPath(shadowBrush, shadowPath);
            shadowBrush.delete();
            shadowPath.delete();

            var cardBrush = gdip.solidBrush(colors.cardBg);
            graphics.fillPath(cardBrush, cardPath);
            cardBrush.delete();
            
            var accentColor = colors.holiday;
            if(!group.hasHoliday) accentColor = colors.workday;
            var lineBrush = gdip.solidBrush(accentColor);
            var linePath = gdip.path();
            
            graphics.setClipPath(cardPath); 
            graphics.fillRectangle(lineBrush, cardRect.x, cardRect.y, 6*dpiX, cardRect.height);
            graphics.resetClip();
            lineBrush.delete();
            linePath.delete();
            cardPath.delete();
            
            var contentX = cardRect.x + 12*dpiX;
            
            var icon = festivalIcons[group.name] || '\uF0ED';
            var iconBrush = gdip.solidBrush(accentColor);
            graphics.drawString(icon, fontIcon, ::RECTF(contentX, y, 40*dpiX, cardRect.height), strformatLeft, iconBrush);
            iconBrush.delete();
            
            var nameBrush = gdip.solidBrush(colors.textDark);
            graphics.drawString(group.name, fontTitle, ::RECTF(contentX + 35*dpiX, y + 12*dpiY, 100*dpiX, 20*dpiY), strformatLeft, nameBrush);
            nameBrush.delete();
            
            var countText;
            if(group.holidayCount){ 
                countText= string.format("休假 %d 天", group.holidayCount) 
                if(group.workCount > 0)  countText = "休 " + group.holidayCount + " 班 " + group.workCount
            }
            else{
                countText = string.format("补班 %d 天", group.workCount);
            }
            var countBrush = gdip.solidBrush(colors.textLight);
            graphics.drawString(countText, font, ::RECTF(contentX + 35*dpiX, y + 42*dpiY, 100*dpiX, 20*dpiY), strformatLeft, countBrush);
            countBrush.delete();
            
            
            var x = leftMargin - 10*dpiX;
            
            for(j, day in group.days) {
                var blockColor;
                
                if(day.isOffDay === false) {
                    blockColor = colors.workday;
                } elseif(day.isOffDay === 0) {
                    blockColor = colors.normalWork;
                } else {
                    blockColor = colors.holiday;
                }
                
                var bShadowPath = gdip.path();
                bShadowPath.addRoundRect(x + 2*dpiX, y + 2*dpiY, dayWidth - gap, dayHeight, 6*dpiX);
                var bShadowBrush = gdip.solidBrush(colors.shadow);
                graphics.fillPath(bShadowBrush, bShadowPath);
                bShadowBrush.delete();
                bShadowPath.delete();
                
                var path = gdip.path();
                path.addRoundRect(x, y, dayWidth - gap, dayHeight, 6*dpiX);
                var brush = gdip.solidBrush(blockColor);
                graphics.fillPath(brush, path);
                brush.delete();
                path.delete();
                
                var textBrush = gdip.solidBrush(colors.textPrimary);
                
                var dateStr = string.match(day.date, "\d+-(\d+-\d+)");
                graphics.drawString(dateStr, fontDay, ::RECTF(x, y + 8*dpiY, dayWidth - gap, 20*dpiY), strFormat, textBrush);
                
                graphics.drawString(day.lunarDate, font, ::RECTF(x, y + 28*dpiY, dayWidth - gap, 15*dpiY), strFormat, textBrush);
                
                graphics.drawString(day.week, font, ::RECTF(x, y + 44*dpiY, dayWidth - gap, 15*dpiY), strFormat, textBrush);
                
                textBrush.delete();
                
                if(day.festival) {
                    var festivalPath = gdip.path();
                    var dRight = x + dayWidth - gap;
                    festivalPath.addEllipse(dRight - 13*dpiX , y + 4*dpiY, 8*dpiX, 8*dpiY);
                    var festivalBrush = gdip.solidBrush(colors.festival);
                    graphics.fillPath(festivalBrush, festivalPath);
                    festivalBrush.delete();
                    festivalPath.delete();
                }
                
                x = x + dayWidth;
            }
        }
        
        y = y + rowHeight;
    }
    
    strFormat.delete();
    strformatLeft.delete();
    fontTitle.delete();
    fontDay.delete();
    fontIcon.delete();
    
    return true;
};

winform.holidayView.onMouseWheel = function(flags, delta, lParam) {
    scrollY = scrollY - delta / 3;
    scrollY = math.max(0, math.min(scrollY, maxScrollY));
    owner.redraw();
};

winform.comboYear.onSelChange = function() {
    var yearText = winform.comboYear.selText;
    var year = tonumber(yearText);

    if(year) {
        loadHolidays(year);
        winform.holidayView.redraw();
        updateDate();
    }
};

import time.lunar;
import time.festival;
updateDate = function(){
    var now = time.now();
    var lunar = time.lunar(now);
    
    var festival = time.festival.getName(now);
    
    var text = tostring(lunar,"%Y/%m/%d %H:%M %LH时 %Ly年%Lm%Ld %a");  
    if(festival) text = text + "  |  " + festival;  
    if(#todayStatus) text = text + "  |  " + todayStatus; 
    
    winform.lbToday.text = text;
}

winform.setInterval(updateDate,2000)    
loadHolidays(currentYear);
updateDate();

winform.show();
win.loopMessage();
```

