Add new comment

16
Jan

Faça sua própria agenda com LaTeX!

No final da página você encontra um link para o documento que iremos produzir.

Nesse artigo, tentarei começar com os códigos básicos e ir recheando de acordo com as intenções de cada etapa. Primeiramente, a classe escolhida foi a mais simples (article) com as seguintes opções:

  • a4paper: papel A4
  • landscape: folha com orientação paisagem

Não vou me preocupar com as margens do documento impostas pela classe, pois iremos atropelá-las com a ajuda de um pacote chamado "TikZ". Se você ainda não o conhece, dê uma olhada neste site e terá ideia do tamanho do poder desta ferramenta que fará todo o trabalho duro neste projeto. Além dele,  alguns pacotes para tratar codificação de entrada (inputenc) e de saída (fontenc), a separação das palavras (babel) e para facilitar cálculos (calc) foram incluídos. Dessa forma, nosso código mínimo ficará assim.

\documentclass[a4paper, landscape]{article}
\usepackage[utf8]{inputenc} % para windows: \usepackage[latin1]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[brazilian]{babel}
\usepackage{calc}
\usepackage{tikz}

\begin{document}

\end{document}

Bom, com infraestrutura montada, agora precisamos começar a implementar a agenda em si. O próprio TikZ possui algumas coisas prontas para isso, mas não serão suficientes aqui. Por isso, entraremos em contato com uma parte um pouco mais profunda que é o PGF, que em uma analogia razoável seria o framework para o TikZ. É necessário, então, adicionar a biblioteca "calendar" do TikZ . O comando utilizado será o

\pgfcalendar{ prefixo }{ data inicial }{ data final }{ código }

Explicando melhor cada campo:

  • prefixo: como o pgf cria automaticamente o calendário por meio de iterações e usa o campo prefixo para gerar os nomes.
  • data inicial e data final: isso mesmo.
  • código: é o trecho de código executado para cada um dos dias do intervalo.

E aproveitando esse interlúdio, vou aproveitar para mostrar alguns comandos que serão úteis:

  • \pgfcalendarcurrentday imprime o dia da iteração (de 1 até o último dia do mês)
  • \pgfcalendarcurrentweekday imprime o valor numérico do dia da semana (de 0 a 6).
  • \ifdate{condicao}{se}{senao} com este comando, testa-se as datas. Esse comando reconhece como condição os dias da semana, dias do mes, intervalos, e algumas coisinhas mais que podem ser verificadas na página 510 do manual (TikZ versão 2.1).

No próximo código, faremos um calendário semanal (prefiro este tipo, pois posso ter uma visão geral da semana toda). Vale ressaltar que, para diminuir o número de cálculos nessas versões iniciais, usarei o período mais curto, de dois meses, que servirá como  exemplo. As datas são escritas da forma invertida (ano-mes-dia) e a opção "ano-mes-last" representa o último dia de um determinado mês, já que isso varia.

\documentclass[a4paper, landscape] {article}

\usepackage[utf8]{inputenc} % para windows: \usepackage[latin1]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[brazilian]{babel}
\usepackage{calc}

\usepackage{tikz}
    \usetikzlibrary{calendar}

\begin{document}
    \pgfcalendar{cal}{2012-1-1}{2012-2-last}{
        \ifdate{Monday}{\clearpage}{}
        \pgfcalendarcurrentday
    }
\end{document}

Como você pôde perceber, ao processar esse código, uma nova página era criada a cada segunda-feira. Porém, devido às margens impostas pela memoir, o conteúdo fica sambando de um lado para o outro. Para evitar isso, faremos uso do posicionamento absoluto (current page, remember picture, overlay) oferecido pelo TikZ.

Além disso, é saudável que os dias do mês estejam organizados de acordo com os dias da semana. No próximo passo, criaremos um ponto no canto superior esquerdo, chamado de "base", que será usado como referência. A partir dele, outros nós são posicionados s usando uma distância (\fieldsize) relativamente ao dia da semana. Por exemplo, a "segunda" vai ficar sobre o ponto de referência, a "terça" será deslocada de um "\fieldsize", a quarta de dois "\fieldsize", e por aí vai. Depois que os dias da semana estão posicionados, é só colocar os dias do mês abaixo deles.

Outras observações importantes:

  • \pgfcalendarweekdayname{número do dia da semana} imprime o nome do dia da semana de acordo com o parâmetro (0 a 6).
  • \pagestyle{empty} retira o número da página.
  • \usetikzlibrary{positioning} inclui uma biblioteca que aumenta as capacidades de posicionamento dos nós do TikZ (por exemplo, right = "distância" of "nó").
  • \pgfmathsetlengthmacro{macro}{expressão} nas entranhas do pgf existe muita capacidade matemática. Aqui ela é usada para calcular uma certa expressão e atribuir o valor resultante a uma macro, que não precisa estar declarada anteriormente.
  • \coordinate (nome) at (coordenadas); atribui um nome à coordenada.
  • \node {}; essa é a estrutura básica de um nó, que permite escrever algo em determinado local. Mas como poderá ser visto, existem muitas opções, recomendo uma leitura rápida da seção 3.3 do terceiro tutorial do manual.

\documentclass[a4paper, landscape] {article}

\usepackage[utf8]{inputenc} % para windows: \usepackage[latin1]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[brazilian]{babel}
\usepackage{calc}

\usepackage{tikz}
    \usetikzlibrary{calendar}
    \usetikzlibrary{positioning}

\pagestyle{empty}

\begin{document}
    \newlength{\fieldsize}
    \setlength{\fieldsize}{4.1cm}
    
    \pgfcalendar{cal}{2012-1-1}{2012-2-last}{
        \ifdate{Monday}{\clearpage}{}
        \pgfmathsetlengthmacro{\absolutespaceweekday}{\fieldsize * \pgfcalendarcurrentweekday}
        \begin{tikzpicture} [remember picture, overlay]
            \coordinate [xshift = 0.5cm , yshift = -3cm] (base) at (current page.north west);
            \node [right = \absolutespaceweekday of base, minimum width = \fieldsize] (temp) {};
            \node at (temp.center) {\pgfcalendarweekdayname{\pgfcalendarcurrentweekday}};
            \node [below = 0.5cm of temp, minimum width = \fieldsize] (temp) {};
            \node at (temp.center) {\pgfcalendarcurrentday};
        \end{tikzpicture}
    }
\end{document}

E agora já é possível ver o calendário tomando forma. Como "agenda que é agenda" facilita a marcação de horários, incluirei uma linha para cada hora do dia. Para tanto, usarei mais um recurso pouco conhecido no LaTeX, o laço de repetição (foreach) que explico melhor abaixo. Em cada iteração, incluo um nó (node) com um determinado tamanho e uso suas coordenadas inferiores ("south west" e "south east") para fazer uma linha (draw) e sua cordenada oest (west) para incluir a hora. Além disso, para que as semanas não fiquem soltas, é necessário também que um título seja colocado com o nome do mês em questão. Para isso, novamente usa-se o recurso de posicionamento absoluto do TikZ.

Outras observações:

  • \newcounter{<contador>} uma variável para armazenar a hora que será inserida.
  • \the<contador> imprime o valor do contador
  • \pgfcalendarcurrentmonth imprime o número do mês atual (de 1 a 12)
  • \pgfcalendarmonthname{<númermo do mês>} imprime o nome do mês de acordo com o parâmetro (1 a 12).
  • \fontsize{<tamanho>}{<tamanho>} \selectfont falando bem simplificadamente, altera tamanho da fonte dentro do nó.
  • \foreach <var> in {<intervalo>} {<código>} repete o código para cada valor da variável no intervalo.

Segue o código atualizado:

\documentclass[a4paper, landscape]{article}

\usepackage[utf8]{inputenc} % para windows: \usepackage[latin1]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[brazilian]{babel}
\usepackage{calc}

\usepackage{tikz}
    \usetikzlibrary{calendar}
    \usetikzlibrary{positioning}

\pagestyle{empty}

\newcounter{hour}

\begin{document}
    \newlength{\fieldsize}
    \setlength{\fieldsize}{4.1cm}
    
    \pgfcalendar{cal}{2012-1-1}{2012-2-last}{
        \ifdate{Monday}{
            \clearpage
            \tikz[remember picture, overlay]
                \node [anchor = north, yshift = -0.5cm, inner ysep = 0pt] at (current page.north) {\fontsize{1.5cm}{1.5cm} \selectfont \pgfcalendarmonthname{\pgfcalendarcurrentmonth}};
        }{}
        \pgfmathsetlengthmacro{\absolutespaceweekday}{\fieldsize * \pgfcalendarcurrentweekday}
        \begin{tikzpicture} [remember picture, overlay]
            \coordinate [xshift = 0.5cm , yshift = -3cm] (base) at (current page.north west);
            \node [right = \absolutespaceweekday of base, minimum width = \fieldsize] (temp) {};
            \node at (temp.center) {\pgfcalendarweekdayname{\pgfcalendarcurrentweekday}};
            \node [below = 0.5cm of temp, minimum width = \fieldsize] (temp) {};
            \node at (temp.center) {\pgfcalendarcurrentday};
            \foreach \hl in {1,...,24} {
                \node [below = 0.65 * \hl cm of temp, minimum width = 0.95\fieldsize] (temp2) {};
                \draw (temp2.south west) -- (temp2.south east);
                \setcounter{hour}{\hl - 1}
                \node [anchor = west, yshift  = 0.1cm] at (temp2.west) {\thehour};
            }
        \end{tikzpicture}
    }
\end{document}

Bom, pode-se dizer que a agenda está finalizada. Porém, para mim os nomes apareceram em inglês, o que significa que o recurso de tradução oferecido pelo TikZ, e atrelado ao pacote babel, não funcionou. Existe uma solução simples, mas um pouco trabalhosa para isso. É só testar cada dia da semana e mês, atribuindo valores adequados a novas variáveis que serão impressas no lugar dos recursos oferecidos pela biblioteca calendar do TikZ. Segue a versão final do código. Não se esqueçam de mudar o intervalo do calendário produzido!

Ah! E como o ano não começa numa segunda e consequentemente, a primeira semana fica sem título. Então, coloquei um comando antes de tudo com a finalidade de corrigir essa pequena falha. É fácil de identificá-lo.

\documentclass[a4paper, landscape] {article}

\usepackage[utf8]{inputenc} % para windows: \usepackage[latin1]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[brazilian]{babel}
\usepackage{calc}

\usepackage{tikz}
    \usetikzlibrary{calendar}
    \usetikzlibrary{positioning}

\pagestyle{empty}

\newlength{\fieldsize}
\newcounter{hour}
\newcommand{\weekday}{}
\newcommand{\monthname}{}

\begin{document}
    \setlength{\fieldsize}{4.1cm}

    \tikz[remember picture, overlay]
      \node [anchor = north, yshift = -0.5cm, inner ysep = 0pt] at (current page.north) {\fontsize{1.5cm}{1.5cm} \selectfont Janeiro};

   
    \pgfcalendar{cal}{2012-1-1}{2012-12-last}{
        \ifdate{Monday}{\renewcommand{\weekday}{Segunda}}{}
        \ifdate{Tuesday}{\renewcommand{\weekday}{Terça}}{}
        \ifdate{Wednesday}{\renewcommand{\weekday}{Quarta}}{}
        \ifdate{Thursday}{\renewcommand{\weekday}{Quinta}}{}
        \ifdate{Friday}{\renewcommand{\weekday}{Sexta}}{}
        \ifdate{Saturday}{\renewcommand{\weekday}{Sábado}}{}
        \ifdate{Sunday}{\renewcommand{\weekday}{Domingo}}{}

        \ifdate{between=1-1 and 1-last}{\renewcommand{\monthname}{Janeiro}}{}
        \ifdate{between=2-1 and 2-last}{\renewcommand{\monthname}{Fevereiro}}{}
        \ifdate{between=3-1 and 3-last}{\renewcommand{\monthname}{Março}}{}
        \ifdate{between=4-1 and 4-last}{\renewcommand{\monthname}{Abril}}{}
        \ifdate{between=5-1 and 5-last}{\renewcommand{\monthname}{Maio}}{}
        \ifdate{between=6-1 and 6-last}{\renewcommand{\monthname}{Junho}}{}
        \ifdate{between=7-1 and 7-last}{\renewcommand{\monthname}{Julho}}{}
        \ifdate{between=8-1 and 8-last}{\renewcommand{\monthname}{Agosto}}{}
        \ifdate{between=9-1 and 9-last}{\renewcommand{\monthname}{Setembro}}{}
        \ifdate{between=10-1 and 10-last}{\renewcommand{\monthname}{Outubro}}{}
        \ifdate{between=11-1 and 11-last}{\renewcommand{\monthname}{Novembro}}{}
        \ifdate{between=12-1 and 12-last}{\renewcommand{\monthname}{Dezembro}}{}

        \ifdate{Monday}{
            \clearpage
            \tikz[remember picture, overlay]
                \node [anchor = north, yshift = -0.5cm, inner ysep = 0pt] at (current page.north) {\fontsize{1.5cm}{1.5cm} \selectfont \monthname};
        }{}
        \pgfmathsetlengthmacro{\absolutespaceweekday}{\fieldsize * \pgfcalendarcurrentweekday}
        \begin{tikzpicture} [remember picture, overlay]
            \coordinate [xshift = 0.5cm , yshift = -3cm] (base) at (current page.north west);
            \node [right = \absolutespaceweekday of base, minimum width = \fieldsize] (temp) {};
            \node at (temp.center) {\weekday};
            \node [below = 0.5cm of temp, minimum width = \fieldsize] (temp) {};
            \node at (temp.center) {\pgfcalendarcurrentday};
            \foreach \hl in {1,...,24} {
                \node [below = 0.65 * \hl cm of temp, minimum width = 0.95\fieldsize] (temp2) {};
                \draw (temp2.south west) -- (temp2.south east);
                \setcounter{hour}{\hl - 1}
                \node [anchor = west, yshift  = 0.1cm] at (temp2.west) {\thehour};
            }
        \end{tikzpicture}
    }
\end{document}

 

Portuguese, Brazil
Tipo: