EyeTimer 0.1 - знакомимся с SWHX и Arctic

Своё знакомство с SWHX я решил начать с создания простого, но полезного приложения, аналогом которого довольно часто пользуюсь при работе в Ubuntu - там в Gnome есть возможность поставить себе регулярное напоминание о том, что пора отдохнуть, блокирующее экран на заданное время, дабы сберечь свои глаза.

Для этих же целей пока служит и EyeTimer (в будущем собираюсь построить на его основе более сложное и интересное приложение), так что теперь у меня будет такое же приложение и под Windows в которой приходится работать гораздо чаще и дольше (а если понадобится, то и для Mac, SWHX позволяет), но уже своё собственное, что, конечно, приятно.

Суть работы EyeTimer проста - при запуске вы задаёте время работы и отдыха в минутах и приложения чередует периоды, во время отдыха перекрывая экран полу-прозрачным flash окном с отсчётом оставшегося на отдых времени, тем самым помогая вам спасти себя от всяких непритных вещей типа "сухого глаза" и просто слишком долгого сидения за компьютером.

Заканчиваем с лирикой, переходим к технической части.
Итак, EyeTimer построен на основе SWHX - библиотеки для создания десктоп приложений, использующих Flash в качестве основы для интерфейса.
Flash интерфейс я сделал на платформе flash9, а в качестве GUI-библиотеки использовал Arctic. В принципе, с таким же успехом (а может и проще) было использовать готовый отрисованный UI или Flex, но мне нравится Arctic, так что я заодно решил в нём ещё раз попрактиковаться.

Если вдруг кто-то не знает как устанавливать библиотеки для haXe, могу сказать, что это очень сложно :)

haxelib install swhx
haxelib install arctic

Ссылка на архив с приложением и исходниками прилагается к этой странице (в самом низу), а здесь размещу код только одного из двух классов, того, что компилируется в neko и является сервером для EyeTimer:

import neko.net.RemotingServer;
import systools.win.Events;
import swhx.MessageHook;
import systools.Key;
import systools.Misc;
import swhx.Window;
 
class App
{
        static var server       :RemotingServer;
        static var window       :swhx.Window;           // окно приложения
        static var flash        :swhx.Flash;            // объект flash
        static var cnx          :swhx.Connection;       // соединение с flash UI
       
        static var keyboardHook :MessageHook;
       
        static var WORK_TIME :Float = 45;
        static var REST_TIME :Float = 15;
        static var CANCEL_TIME :Float = 15; // время на которое откладывается отдых (сек)
       
        static function main()
        {
                swhx.Application.init();
                var screen = systools.Display.getScreenSize();
                window = new swhx.Window( "Time to...", screen.w, screen.h, Window.WF_ALWAYS_ONTOP | Window.WF_PLAIN | swhx.Window.WF_TRANSPARENT );
                window.onRightClick = function() { return false; }; // блок контекстного меню flash
                server = new RemotingServer();
                server.addObject("serverSide", App);
               
                flash = new swhx.Flash( window, server );
                flash.setAttribute( "src", "win.swf" );
                flash.setAttribute( "FlashVars", "worktime="+WORK_TIME+"&resttime="+REST_TIME );
                flash.onSourceLoaded = onSourceLoaded;
                flash.start();
                // хук для отлова событий клавиатуры:
                keyboardHook = window.addMessageHook(untyped Events.KEYDOWN);
                keyboardHook.setNekoCallback(keyDownHook);
               
                window.visible = true;         
                swhx.Application.loop();               
               
        }
       
        static function onSourceLoaded() {
                cnx = swhx.Connection.flashConnect(flash);             
        }
       
       
        // посылает клиенту команду показать окно конфигурации
        static function showConfigWindow ()
        {
                cnx.Win.showConfig.call([WORK_TIME, REST_TIME]);
                window.visible = true;
        }
       
        // посылает клиенту команду открыть заставку и запустить таймер отдыха
        static function startRestWindow ()
        {
                cnx.Win.startRestTimer.call([REST_TIME]);
                window.visible = true;
        }
       
       
       
// -------------- обработчики --------------
       
        // вызывается с клиента нажатием кнопки Start (запустить программу из конфига)
        static function onStartWork (?wtime, ?rtime)
        {
                trace('onStartWork');
                if (wtime != 0) WORK_TIME = wtime *60;
                if (rtime != 0) REST_TIME = rtime *60;
                window.visible = false;
                setTimeout(startRestWindow, WORK_TIME);
        }

        // вызывается с клиента нажатием кнопки Cancel (отложить отдых)
        static function onCancel ()
        {
                window.visible = false;
                setTimeout(startRestWindow, CANCEL_TIME);
        }      
       
       
        // обработчик нажатий на клавиатуру
        static function keyDownHook() {
                if (Misc.getKeyState(Key.Custom(27))) cleanUp(); // Esc                
                return 0;
        }
       
// ------------ внутренние --------------------
       
        // очистка ресурсов перед выгрузкой приложения
        static private function cleanUp () {
                window.removeMessageHook(keyboardHook);
                window.removeMessageHook(rbuttonHook);
                swhx.Application.cleanup();
        }
       
        //
        static private function setTimeout(action, timeout)
        {
                neko.vm.Thread.create(
                        function () {
                                neko.Sys.sleep(timeout);
                                action();
                        }
                );             
        }      
}