Pull to refresh

Виджет «Бинарные часы» для Awesome

Reading time8 min
Views5K
Как я дошел до жизни такой

Все началось с перехода на новое место работы. Хотя, нет… Все началось с Марлы со случайно увиденного где-то изображения с чудо-часами. Это изображение меня заинтересовало, я обратился к помощи википедии, и открыл для себя такую чудесную вещь, как бинарные часы (Binary-coded decimal clocks), после чего я, тогда изучавший в свободное время Java, настолько проникся этой концепцией отображения времени, что даже написал простенькое приложение с бинарными часами. Время шло, приложение то давно забылось, бинарные часы временно выпали из моего поля зрения и уютно устроились на чердаке памяти. Но тут череда событий перетряхнула этот чердак, и мысль о бинарных часах снова пошла в обработку мозгом.

Главным событием стала смена работы, и последовавшая вместе с ней смена 17-дюймового монитора на 23-дюймовый. После пары недель работы стало абсолютно ясно, что используемый мной уже не один год Gnome не позволяет полноценно использовать все доступное мне пространство рабочего стола (1920*1080, это ж и подумать было страшно о таком разрешении на мониторе еще лет 10 назад). Фигурно расставлять окна довольно неудобно, а специфика работы системного администратора в моей организации подразумевает одновременное открытие и параллельное использование как минимум консоли, браузера, мессенджера, а так же еще кучи меняющихся в зависимости от контекста деятельности приложений, таких как rdesktop или vncviewer.

Как раз в этот момент я в очередной раз наткнулся на упоминание о тайловых менеджерах рабочего стола, и решил испробовать данный способ организации рабочего пространства. И о чудо — это оказалось весьма удобно. Испробовав несколько WM, я остановил свой выбор на Awesome. Через пару дней использования, я уверился в мысли о том, что именно такой тип WM как нельзя лучше подходит мне для работы, а awesome является достойным представителем данного типа, и принялся изучать возможность кастомизации своего рабочего стола. На мое счастье, Awesome начиная с третьей версии использует скрипт на языке Lua для конфигурации, что позволяет писать виджеты прямо в конфиге. Изучая доступные на сайте Awesome виджеты от пользователей, я наткнулся на виджет аналоговых часов, и беглый просмотр кода этого виджета показал мне отличную возможность реализовать давно интересующую меня вещь — бинарные часы, вместо стандартных для awesome текстовых. Все, что необходимо для этого — возможность рисовать изображение средствами самого Awesome, так что виджет не зависит от внешних компонентов.

image:draw_rectangle(x,y,w,h)

Конечно, язык Lua я до этого ни разу не использовал, но задача представлялась весьма тривиальной, так что я принялся за работу.

Итак, поехали

Открываем в текстовом редакторе нужный нам файл:

$vim ~/.config/awesome/rc.lua

Ищем имеющееся объявление виджета текстовых часов

mytextclock = awful.widget.textclock({ align = "right" })


И начинаем «творить»:

binaryclock = {}
binaryclock.widget = widget({type = "imagebox"})
binaryclock.w = 51 --width 
binaryclock.h = 24 --height (better to be a multiple of 6)
--dont forget that awesome resizes our image with clocks to fit wibox's height
binaryclock.show_sec = true --must we show seconds? 
binaryclock.color_active = beautiful.bg_focus --active dot color
binaryclock.color_bg = beautiful.bg_normal --background color
binaryclock.color_inactive = beautiful.fg_focus --inactive dot color
binaryclock.dotsize = math.floor(binaryclock.h / 6) --dot size
binaryclock.step = math.floor(binaryclock.dotsize / 2) --whitespace between dots
binaryclock.widget.image = image.argb32(binaryclock.w, binaryclock.h, nil) --create image
if (binaryclock.show_sec) then binaryclock.timeout = 1 else binaryclock.timeout = 20 end --we don't need to update often when we don't show seconds


Как вы видите, все настройки виджета задаются здесь, и все основные расчеты размеров проводятся тут же.
Дальше я использовал уже готовое решение для языка Lua, позволяющее переводить числа в десятичной системе исчисления в любую другую:
binaryclock.DEC_BIN = function(IN) --thanx to Lostgallifreyan (http://lua-users.org/lists/lua-l/2004-09/msg00054.html)
    local B,K,OUT,I,D=2,"01","",0
    while IN>0 do
        I=I+1
        IN,D=math.floor(IN/B),math.mod(IN,B)+1
        OUT=string.sub(K,D,D)..OUT
    end
    return OUT
end


Теперь объявим функцию, рисующую точки-«диоды» часов, соответственно самому числу
binaryclock.paintdot = function(val,shift,limit) --paint number as dots with shift from left side
      local binval = binaryclock.DEC_BIN(val)
      local l = string.len(binval)
      local height = 0 --height adjustment, if you need to lift dots up
      if (< limit) then
             for i=1,limit - l do binval = "0" .. binval end
      end
      for i=0,limit-1 do
             if (string.sub(binval,limit-i,limit-i) == "1") then
                   binaryclock.widget.image:draw_rectangle(shift,  binaryclock.h - binaryclock.dotsize - height, binaryclock.dotsize, binaryclock.dotsize, true, binaryclock.color_active)
             else
                   binaryclock.widget.image:draw_rectangle(shift,  binaryclock.h - binaryclock.dotsize - height, binaryclock.dotsize,binaryclock.dotsize, true, binaryclock.color_inactive)
             end
             height = height + binaryclock.dotsize + binaryclock.step
       end
  end


Ну и наконец главная функция, рисующая наши часики:

binaryclock.drawclock = function () --get time and send digits to paintdot()
      binaryclock.widget.image:draw_rectangle(00, binaryclock.w, binaryclock.h, true, binaryclock.color_bg) --fill background
      local t = os.date("*t")
      local hour = t.hour
      if (string.len(hour) == 1) then
             hour = "0" .. t.hour
      end
      local min = t.min
      if (string.len(min) == 1) then
             min = "0" .. t.min
      end
      local sec = t.sec
      if (string.len(sec) == 1) then
             sec = "0" .. t.sec
      end
      local col_count = 6
      if (not binaryclock.show_sec) then col_count = 4 end
      local step = math.floor((binaryclock.w - col_count * binaryclock.dotsize) / 8) --calc horizontal whitespace between cols
      binaryclock.paintdot(0 + string.sub(hour, 11), step, 2)
      binaryclock.paintdot(0 + string.sub(hour, 22), binaryclock.dotsize + 2 * step, 4)
      binaryclock.paintdot(0 + string.sub(min11),binaryclock.dotsize * 2 + 4 * step, 3)
      binaryclock.paintdot(0 + string.sub(min22),binaryclock.dotsize * 3 + 5 * step, 4)
      if (binaryclock.show_sec) then
             binaryclock.paintdot(0 + string.sub(sec, 11), binaryclock.dotsize * 4 + 7 * step, 3)
             binaryclock.paintdot(0 + string.sub(sec, 22), binaryclock.dotsize * 5 + 8 * step, 4)
      end
      binaryclock.widget.image = binaryclock.widget.image
  end


Конечно, не самое элегантное решение, но работает.
Нам осталось только установить таймер обновления:

binarytimer = timer { timeout = binaryclock.timeout } --register timer
  binarytimer:add_signal("timeout"function()
      binaryclock.drawclock()
  end)
  binarytimer:start()--start timer


и разместить наш виджет на панели (вибоксе):
mywibox[s].widgets = {
        --widgets
        binaryclock.widget,
        --widgets again
        layout = awful.widget.layout.horizontal.rightleft
    }


Хотя для пущей красоты (и нормального размера часов на Full-HD экране), мне пришлось еще изменить высоту панели:
mywibox[s] = awful.wibox({ position = "top", screen = s, height = "22" })


Пусть вас не удивляет высота панели в 22px, при высоте виджета в 24. Awesome масштабирует изображения в панели, но почему-то при высоте панели 24px иконка Pidgin в трее ведет себя очень склочно, мигает, и вообще капризничает.
Работа закончена, можно оценить результат, перезапустив Awesome чудесным комбо Mod4+Ctrl+r.

И что же в итоге?

Результат моего труда вы можете оценить на скриншоте:

Пара дней написания кода в обеденный перерыв — и бинарные часы благополучно замигали, показывая время в панели awesome, а я обогатился знаниями о языке Lua, и украсил свое виртуальное рабочее пространство. Awesome, кстати, так же показал свою пригодность к использованию и на моем 11-дюймовом ноутбуке, позволив мне почти полностью отказаться от использования тачпада/трекпада, и увеличить общую отзывчивость ноутбука.

P.S. Код виджета в ближайшее время будет опубликован мной в вики проекта Awesome по следующему адресу. Для написания использовался awesome v3.4.10 (Exploder).
Tags:
Hubs:
Total votes 40: ↑39 and ↓1+38
Comments22

Articles