1 | #include "TRTransfer.h" |
---|
2 | |
---|
3 | #include <Font.h> |
---|
4 | |
---|
5 | #include <malloc.h> |
---|
6 | #include <stdio.h> |
---|
7 | |
---|
8 | /** |
---|
9 | * BListItem that renders Transfer status. |
---|
10 | */ |
---|
11 | TRTransfer::TRTransfer(const char *fullpath, node_ref node) : BListItem(0, false), cachedNodeRef(node) { |
---|
12 | fBaselineOffset = 0.0f; |
---|
13 | fLineSpacing = 0.0f; |
---|
14 | |
---|
15 | cachedPath = new BString(fullpath); |
---|
16 | fStatusLock = new BLocker("Status Locker", true); |
---|
17 | |
---|
18 | fStatus = (tr_stat_t*)calloc(1, sizeof(tr_stat_t)); |
---|
19 | |
---|
20 | fBarColor.red = 50; |
---|
21 | fBarColor.green = 150; |
---|
22 | fBarColor.blue = 255; |
---|
23 | fBarColor.alpha = 255; |
---|
24 | |
---|
25 | fTimeStr = (char*)calloc(78, sizeof(char)); |
---|
26 | fTransStr = (char*)calloc(78, sizeof(char)); |
---|
27 | } |
---|
28 | |
---|
29 | |
---|
30 | TRTransfer::~TRTransfer() { |
---|
31 | if (fStatusLock->Lock()) { |
---|
32 | free(fStatus); |
---|
33 | fStatusLock->Unlock(); |
---|
34 | delete fStatusLock; |
---|
35 | } |
---|
36 | delete cachedPath; |
---|
37 | } |
---|
38 | |
---|
39 | |
---|
40 | void TRTransfer::Update(BView *owner, const BFont *font) { |
---|
41 | BListItem::Update(owner, font); |
---|
42 | SetHeight(BListItem::Height() * 4); |
---|
43 | |
---|
44 | font_height height; |
---|
45 | font->GetHeight(&height); |
---|
46 | |
---|
47 | fBaselineOffset = height.leading + height.ascent; |
---|
48 | fLineSpacing = height.descent; |
---|
49 | } |
---|
50 | |
---|
51 | |
---|
52 | /** |
---|
53 | * Sets the transfer information to render. |
---|
54 | * Returns a bool signaling the view is dirty after the update. |
---|
55 | * |
---|
56 | * The view is determined to be dirty if the transfer |
---|
57 | * status, progress, eta or the "shade" (even or odd) |
---|
58 | * position in the list changes from the previous state. |
---|
59 | * If the tr_stat_t is in fact different then the new, full |
---|
60 | * status is memcpy'd overtop the existing code. |
---|
61 | * |
---|
62 | * This is a thread-safe function, as all writing to the |
---|
63 | * local fStatus requires a successful Lock on fStatusLock. |
---|
64 | */ |
---|
65 | bool TRTransfer::SetStatus(tr_stat_t *stat, bool shade) { |
---|
66 | bool dirty = false; |
---|
67 | if (fStatusLock->Lock()) { |
---|
68 | if (fStatus->status != stat->status || |
---|
69 | fStatus->progress != stat->progress || |
---|
70 | fStatus->eta != stat->eta || |
---|
71 | fShade != shade) |
---|
72 | { |
---|
73 | memcpy(fStatus, stat, sizeof(tr_stat_t)); |
---|
74 | dirty = true; |
---|
75 | } |
---|
76 | fStatusLock->Unlock(); |
---|
77 | fShade = shade; |
---|
78 | } |
---|
79 | return dirty; |
---|
80 | } |
---|
81 | |
---|
82 | |
---|
83 | /** |
---|
84 | * Renders (Draws) the current status into the BListView. |
---|
85 | */ |
---|
86 | void TRTransfer::DrawItem(BView *owner, BRect frame, bool complete) { |
---|
87 | rgb_color col; |
---|
88 | col.red = 255; |
---|
89 | col.green = 255; |
---|
90 | col.blue = 255; |
---|
91 | |
---|
92 | owner->PushState(); |
---|
93 | |
---|
94 | // Draw the background... |
---|
95 | if (IsSelected()) { |
---|
96 | owner->SetLowColor(tint_color(col, B_DARKEN_2_TINT)); |
---|
97 | } else if (fShade) { |
---|
98 | owner->SetLowColor(tint_color(tint_color(col, B_DARKEN_1_TINT), B_LIGHTEN_2_TINT)); |
---|
99 | } else { |
---|
100 | owner->SetLowColor(col); |
---|
101 | } |
---|
102 | owner->FillRect(frame, B_SOLID_LOW); |
---|
103 | |
---|
104 | // Draw the informational text... |
---|
105 | owner->SetHighColor(ui_color(B_MENU_ITEM_TEXT_COLOR)); |
---|
106 | BPoint textLoc = frame.LeftTop(); |
---|
107 | textLoc.y += (fBaselineOffset / 2); |
---|
108 | textLoc += BPoint(2, fBaselineOffset); |
---|
109 | |
---|
110 | if (fStatus != NULL && fStatusLock->Lock()) { |
---|
111 | owner->DrawString(fStatus->info.name, textLoc); |
---|
112 | |
---|
113 | if (fStatus->status & TR_STATUS_PAUSE ) { |
---|
114 | sprintf(fTimeStr, "Paused (%.2f %%)", 100 * fStatus->progress); |
---|
115 | } else if (fStatus->status & TR_STATUS_CHECK ) { |
---|
116 | sprintf(fTimeStr, "Checking Existing Files (%.2f %%)", |
---|
117 | 100 * fStatus->progress); |
---|
118 | } else if (fStatus->status & TR_STATUS_DOWNLOAD) { |
---|
119 | if (fStatus->eta < 0 ) { |
---|
120 | sprintf(fTimeStr, "--:--:-- Remaining (%.2f %%Complete)", |
---|
121 | 100 * fStatus->progress); |
---|
122 | } else { |
---|
123 | sprintf(fTimeStr, "%02d:%02d:%02d Remaining (%.2f %%Complete)", |
---|
124 | fStatus->eta / 3600, (fStatus->eta / 60) % 60, |
---|
125 | fStatus->eta % 60, 100 * fStatus->progress); |
---|
126 | } |
---|
127 | } else if (fStatus->status & TR_STATUS_SEED) { |
---|
128 | sprintf(fTimeStr, "Seeding"); |
---|
129 | } else if (fStatus->status & TR_STATUS_STOPPING) { |
---|
130 | sprintf(fTimeStr, "Stopping..."); |
---|
131 | } else { |
---|
132 | fTimeStr[0] = '\0'; |
---|
133 | } |
---|
134 | |
---|
135 | textLoc.x = frame.Width() - owner->StringWidth(fTimeStr) - 2; |
---|
136 | owner->DrawString(fTimeStr, textLoc); |
---|
137 | |
---|
138 | if (fStatus->status & (TR_STATUS_DOWNLOAD | TR_STATUS_SEED | TR_STATUS_CHECK )) { |
---|
139 | // Move to the left of the bottom line. |
---|
140 | textLoc.Set(frame.left + 2, |
---|
141 | frame.top + fBaselineOffset * 3 + (2 * fLineSpacing) + (fBaselineOffset / 2)); |
---|
142 | sprintf(fTransStr, "DL: %.2f KB/s (from %i of %i peer%s)", |
---|
143 | fStatus->rateDownload, fStatus->peersUploading, fStatus->peersTotal, |
---|
144 | (fStatus->peersTotal == 1) ? "" : "s"); |
---|
145 | owner->DrawString(fTransStr, textLoc); |
---|
146 | |
---|
147 | sprintf(fTransStr, "UL: %.2f KB/s", fStatus->rateUpload); |
---|
148 | textLoc.x = frame.Width() - owner->StringWidth(fTransStr) - 2; |
---|
149 | owner->DrawString(fTransStr, textLoc); |
---|
150 | } |
---|
151 | |
---|
152 | /* |
---|
153 | * Progress Bar - Mercilessly ripped from the Haiku source code, and |
---|
154 | * modified to handle selection tinting, and list item position shading. |
---|
155 | */ |
---|
156 | // Custom setup (Transmission Added) |
---|
157 | BRect rect(frame.left + 2, frame.top + fBaselineOffset + fLineSpacing + (fBaselineOffset / 2), |
---|
158 | frame.Width() - 2, frame.top + fBaselineOffset * 2 + fLineSpacing + (fBaselineOffset / 2)); |
---|
159 | |
---|
160 | // First bevel |
---|
161 | owner->SetHighColor(tint_color(ui_color ( B_PANEL_BACKGROUND_COLOR ), B_DARKEN_1_TINT)); |
---|
162 | if (IsSelected()) { |
---|
163 | owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT)); |
---|
164 | } |
---|
165 | owner->StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.left, rect.top)); |
---|
166 | owner->StrokeLine(BPoint(rect.right, rect.top)); |
---|
167 | |
---|
168 | owner->SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_2_TINT)); |
---|
169 | if (IsSelected()) { |
---|
170 | owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT)); |
---|
171 | } |
---|
172 | owner->StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), BPoint(rect.right, rect.bottom)); |
---|
173 | owner->StrokeLine(BPoint(rect.right, rect.top + 1.0f)); |
---|
174 | |
---|
175 | rect.InsetBy(1.0f, 1.0f); |
---|
176 | |
---|
177 | // Second bevel |
---|
178 | owner->SetHighColor(tint_color(ui_color ( B_PANEL_BACKGROUND_COLOR ), B_DARKEN_4_TINT)); |
---|
179 | if (IsSelected()) { |
---|
180 | owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT)); |
---|
181 | } |
---|
182 | owner->StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.left, rect.top)); |
---|
183 | owner->StrokeLine(BPoint(rect.right, rect.top)); |
---|
184 | |
---|
185 | owner->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); |
---|
186 | if (IsSelected()) { |
---|
187 | owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT)); |
---|
188 | } |
---|
189 | owner->StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), BPoint(rect.right, rect.bottom)); |
---|
190 | owner->StrokeLine(BPoint(rect.right, rect.top + 1.0f)); |
---|
191 | |
---|
192 | rect.InsetBy(1.0f, 1.0f); |
---|
193 | |
---|
194 | // Filling |
---|
195 | owner->SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_MAX_TINT)); |
---|
196 | if (IsSelected()) { |
---|
197 | owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT)); |
---|
198 | } |
---|
199 | owner->FillRect(rect); |
---|
200 | |
---|
201 | if (fStatus->progress != 0.0f) { |
---|
202 | rect.right = rect.left + (float)ceil(fStatus->progress * (rect.Width() - 4)), |
---|
203 | |
---|
204 | // Bevel |
---|
205 | owner->SetHighColor(tint_color(fBarColor, B_LIGHTEN_2_TINT)); |
---|
206 | if (IsSelected()) { |
---|
207 | owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT)); |
---|
208 | } |
---|
209 | owner->StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.left, rect.top)); |
---|
210 | owner->StrokeLine(BPoint(rect.right, rect.top)); |
---|
211 | |
---|
212 | owner->SetHighColor(tint_color(fBarColor, B_DARKEN_2_TINT)); |
---|
213 | if (IsSelected()) { |
---|
214 | owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT)); |
---|
215 | } |
---|
216 | owner->StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.right, rect.bottom)); |
---|
217 | owner->StrokeLine(BPoint(rect.right, rect.top)); |
---|
218 | |
---|
219 | rect.InsetBy(1.0f, 1.0f); |
---|
220 | |
---|
221 | // Filling |
---|
222 | owner->SetHighColor(fBarColor); |
---|
223 | if (IsSelected()) { |
---|
224 | owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT)); |
---|
225 | } |
---|
226 | owner->FillRect(rect); |
---|
227 | } |
---|
228 | |
---|
229 | fStatusLock->Unlock(); |
---|
230 | } else { |
---|
231 | owner->DrawString("loading...", textLoc); |
---|
232 | } |
---|
233 | |
---|
234 | owner->PopState(); |
---|
235 | } |
---|